<!DOCTYPE html>












  


<html class="theme-next gemini use-motion" lang="zh-CN">
<head><meta name="generator" content="Hexo 3.9.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">












<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">






















<link href="/blog/lib/font-awesome/css/font-awesome.min.css?v=4.7.0" rel="stylesheet" type="text/css">

<link href="/blog/css/main.css?v=6.4.2" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/blog/images/apple-touch-icon-next.png?v=6.4.2">


  <link rel="icon" type="image/png" sizes="32x32" href="/blog/images/favicon-32x32-next.png?v=6.4.2">


  <link rel="icon" type="image/png" sizes="16x16" href="/blog/images/favicon-16x16-next.png?v=6.4.2">


  <link rel="mask-icon" href="/blog/images/logo.svg?v=6.4.2" color="#222">









<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/blog/',
    scheme: 'Gemini',
    version: '6.4.2',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: false,
    fastclick: false,
    lazyload: false,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>


  




  <meta name="description" content="内容主要包括JavaScript、CSS、HTML、HTTP、计算机网络等一些基础的前端技术。">
<meta name="keywords" content="前端基础">
<meta property="og:type" content="article">
<meta property="og:title" content="Web前端基础">
<meta property="og:url" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/index.html">
<meta property="og:site_name" content="厦门工学院">
<meta property="og:description" content="内容主要包括JavaScript、CSS、HTML、HTTP、计算机网络等一些基础的前端技术。">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/proto-chain.png">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/full-proto-chain.png">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/complex-proto-chain.png">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/standard-model.jpeg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/ie-model.jpeg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/default-defer-async.jpg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/default-defer-async.png">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/render-flow.jpeg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/storage-in-stack.jpg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/storage-in-stack-add.jpg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/storage-in-heap.jpg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/copy-in-heap.jpg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/copy-in-stack.jpg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/value-comparison.jpg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/client-height.png">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/offset-height.png">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/scroll-height.png">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/tcp-packet.jpg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/tcp-packet2.jpg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/tcp-flow.jpg">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/sudoku.png">
<meta property="og:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/shuffle.jpg">
<meta property="og:updated_time" content="2024-10-19T14:51:43.140Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Web前端基础">
<meta name="twitter:description" content="内容主要包括JavaScript、CSS、HTML、HTTP、计算机网络等一些基础的前端技术。">
<meta name="twitter:image" content="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/proto-chain.png">






  <link rel="canonical" href="https://xit-edu.cn/2017/11/03/blog/web-front-end-basic/web-front-end-basic/">



<script type="text/javascript" id="page.configurations">
  CONFIG.page = {
    sidebar: "",
  };
</script>

  <title>Web前端基础 | 厦门工学院</title>
  






  <script type="text/javascript">
    var _hmt = _hmt || [];
    (function() {
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?d3f181d3d99fc3c240567d5b682eebd1";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>






  <noscript>
  <style type="text/css">
    .use-motion .motion-element,
    .use-motion .brand,
    .use-motion .menu-item,
    .sidebar-inner,
    .use-motion .post-block,
    .use-motion .pagination,
    .use-motion .comments,
    .use-motion .post-header,
    .use-motion .post-body,
    .use-motion .collection-title { opacity: initial; }

    .use-motion .logo,
    .use-motion .site-title,
    .use-motion .site-subtitle {
      opacity: initial;
      top: initial;
    }

    .use-motion {
      .logo-line-before i { left: initial; }
      .logo-line-after i { right: initial; }
    }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-CN">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/blog/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">厦门工学院</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
    
      
        <p class="site-subtitle">软件研发工作室</p>
      
    
  </div>

  <div class="site-nav-toggle">
    <button aria-label="切换导航栏">
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>



<nav class="site-nav">
  
    <ul id="menu" class="menu">
      
        
        
        
          
          <li class="menu-item menu-item-home">
    <a href="/blog/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-home"></i> <br>首页</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-archives">
    <a href="/blog/archives/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-archive"></i> <br>归档</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-tags">
    <a href="/blog/tags/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-tags"></i> <br>标签</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-categories">
    <a href="/blog/categories/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-th"></i> <br>分类</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-works1">
    <a href="/blog/works1/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-sitemap"></i> <br>H5小游戏1</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-works2">
    <a href="/blog/works2/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-calendar"></i> <br>H5小游戏2</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-fiction">
    <a href="/blog/fiction/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br>大将军归来</a>
  </li>
        
        
        
          
          <li class="menu-item menu-item-about">
    <a href="/blog/about/" rel="section">
      <i class="menu-item-icon fa fa-fw fa-user"></i> <br>关于</a>
  </li>

      
      
    </ul>
  

  

  
</nav>



  



</div>
    </header>

    


    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          
            

          
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://xit-edu.cn/blog/2017/11/03/blog/web-front-end-basic/web-front-end-basic/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="对美好事物的向往，心中要充满强烈的愿望！">
      <meta itemprop="description" content="沉淀下来的知识，才是真正的财富！">
      <meta itemprop="image" content="/blog/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="厦门工学院">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">Web前端基础
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">

            
            
            

            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              

              
                
              

              <time title="创建时间：2017-11-03 12:00:00" itemprop="dateCreated datePublished" datetime="2017-11-03T12:00:00+08:00">2017-11-03</time>
            

            
              

              
                
                <span class="post-meta-divider">|</span>
                

                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                
                  <span class="post-meta-item-text">更新于</span>
                
                <time title="修改时间：2024-10-19 22:51:43" itemprop="dateModified" datetime="2024-10-19T22:51:43+08:00">2024-10-19</time>
              
            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/blog/categories/WEB前端/" itemprop="url" rel="index"><span itemprop="name">WEB前端</span></a></span>

                
                
                  ，
                
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing"><a href="/blog/categories/WEB前端/基础知识/" itemprop="url" rel="index"><span itemprop="name">基础知识</span></a></span>

                
                
              
            </span>
          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>内容主要包括JavaScript、CSS、HTML、HTTP、计算机网络等一些基础的前端技术。</p>
<a id="more"></a>
<h2 id="JS基础"><a href="#JS基础" class="headerlink" title="JS基础"></a>JS基础</h2><h3 id="原型和原型链"><a href="#原型和原型链" class="headerlink" title="原型和原型链"></a>原型和原型链</h3><h4 id="基本理解"><a href="#基本理解" class="headerlink" title="基本理解"></a>基本理解</h4><p>每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象，这个对象就是我们所说的<code>原型</code>，每一个对象都会从原型”继承”属性。正是因为通过这种继承所以产生了原型链。<br>JavaScript默认并不会复制对象的属性，相反，JavaScript 只是在两个对象之间创建一个关联，这样，一个对象就可以通过委托访问另一个对象的属性和函数，所以与其叫继承，委托的说法反而更准确些。</p>
<p><strong>实例、构造函数、原型三者的关系</strong></p>
<p><img src="proto-chain.png"></p>
<p><strong>如下图，蓝色的箭头就是原型链</strong></p>
<p><img src="full-proto-chain.png"></p>
<p><strong>原型链的完整视图</strong></p>
<p><img src="complex-proto-chain.png"></p>
<p>在原型链上查找属性比较耗时，对性能有副作用，这在性能要求苛刻的情况下很重要。另外，试图访问不存在的属性时会遍历整个原型链。<br>错误实践：扩展原生对象的原型<br>经常使用的一个错误实践是扩展 Object.prototype 或其他内置原型。<br>这种技术被称为猴子补丁并且会破坏封装。尽管一些流行的框架（如 Prototype.js）在使用该技术，但仍然没有足够好的理由使用附加的非标准方法来混入内置原型。<br>扩展内置原型的唯一理由是支持 JavaScript 引擎的新特性，如 Array.forEach。</p>
<h4 id="实际应用"><a href="#实际应用" class="headerlink" title="实际应用"></a>实际应用</h4><h5 id="创建对象"><a href="#创建对象" class="headerlink" title="创建对象"></a>创建对象</h5><p>例如：创建一个实例对象<code>let A = new Student()</code></p>
<ol>
<li><code>A</code>是实例对象；<code>Student</code>是构造函数；<code>Student()</code>是执行的构造函数，或者说构造函数立即执行；Student的原型没有体现出来，是一个概念，我们可以称它为<code>Student的原型</code>；<code>let</code>是关键字用来声明变量；<code>new</code>是运算符。</li>
<li>JS创建对象的过程，在创建对象的时候，不会复制对象的属性，而是在实例对象和原型之间建立一种联系。实例对象A的<code>__proto__</code>指向构造函数Student的原型。<code>A.__proto__ 指向 Student.prototype</code>。由此让A和Student产生了联系，原型链也由此而产生。</li>
</ol>
<p>原型链的例子：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">a</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> b = <span class="keyword">new</span> a();</span><br></pre></td></tr></table></figure>
<p><code>b.__proto__ === a.prototype</code> 返回true<br><code>b.__proto__.constructor === a</code> 返回true<br><code>a.prototype.constructor === a</code> 返回true</p>
<p>创建对象的几种方法</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 第一种</span></span><br><span class="line"><span class="keyword">var</span> o1 = &#123;<span class="attr">name</span>:<span class="string">'o1'</span>&#125;</span><br><span class="line"><span class="keyword">var</span> o11 = <span class="keyword">new</span> <span class="built_in">Object</span>(&#123;<span class="attr">name</span>:<span class="string">'o1'</span>&#125;)</span><br><span class="line"><span class="comment">// 第二种</span></span><br><span class="line"><span class="keyword">var</span> M = <span class="function"><span class="keyword">function</span> (<span class="params"></span>)</span>&#123;<span class="keyword">this</span>.name=<span class="string">'o2'</span>&#125;</span><br><span class="line"><span class="keyword">var</span> o2 = <span class="keyword">new</span> M()</span><br></pre></td></tr></table></figure>
<p><strong>new的执行过程</strong></p>
<ol>
<li>创建一个新的空对象newObj。</li>
<li>把newObj的<code>__proto__</code>指向constructorObj的prototype。</li>
<li>把constructorObj的内容执行到newObj里面，让newObj拥有constructorObj的内容。</li>
<li>返回构造好的对象。</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params">name,age</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.name=name;</span><br><span class="line">    <span class="keyword">this</span>.age=age;</span><br><span class="line">&#125;</span><br><span class="line">Person.prototype.say = <span class="function"><span class="keyword">function</span> (<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'hello my name is'</span>,<span class="keyword">this</span>.name,<span class="keyword">this</span>.age)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p1 = <span class="keyword">new</span> Person(<span class="string">'wrl'</span>,<span class="number">18</span>)</span><br><span class="line">p1.say()<span class="comment">//hello my name is wrl 18</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">myNew</span>(<span class="params">constructorObj,...args</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> newObj = &#123;&#125;<span class="comment">//1. 创建一个新的空对象newObj。</span></span><br><span class="line">    newObj.__proto__ = constructorObj.prototype<span class="comment">//2. newObj的__proto__指向constructorObj的prototype。</span></span><br><span class="line">    <span class="keyword">let</span> result = constructorObj.apply(newObj,args)<span class="comment">//3.把constructorObj的内容执行到newObj里面，让newObj拥有constructorObj的内容。</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">typeof</span> result === <span class="string">'object'</span> ? result : newObj<span class="comment">//4.如果constructorObj有返回对象，就用返回的对象。如果constructorObj没有返回对象，则用构造好的newObj。</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p2 = myNew(Person,<span class="string">'dadabai'</span>,<span class="number">20</span>)</span><br><span class="line">p2.say()<span class="comment">//hello my name is dadabai 20</span></span><br></pre></td></tr></table></figure>
<p>myNew还有另外一种写法。这种方法可以不用在myNew里面指定参数，直接利用js的保留字arguments来操作这些参数。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">myNew2</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> newObj = &#123;&#125;<span class="comment">//1. 创建一个新的空对象newObj。</span></span><br><span class="line">    <span class="keyword">let</span> fn = [].shift.call(<span class="built_in">arguments</span>)</span><br><span class="line">    <span class="comment">//arguments是js的保留字，代表了myNew2()括号里面的参数</span></span><br><span class="line">    <span class="comment">//对arguments执行shift操作，这个操作返回第一个参数给fn，并且会影响到原数组。</span></span><br><span class="line">    <span class="comment">//也就是说会返回myNew2(Person,'dadabai',20)的Person，并且让arguments只剩下'dadabai'和20</span></span><br><span class="line">    newObj.__proto__ = fn.prototype<span class="comment">//2. newObj的__proto__指向Person的prototype。</span></span><br><span class="line">    <span class="keyword">let</span> result = fn.apply(newObj,<span class="built_in">arguments</span>)<span class="comment">//3.把Person的内容执行到newObj里面，让newObj拥有Person的内容。</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">typeof</span> result === <span class="string">'object'</span> ? result : newObj<span class="comment">//4.如果Person有返回对象，就用返回的对象。如果Person没有返回对象，则用构造好的newObj。</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 第三种</span></span><br><span class="line"><span class="keyword">var</span> P=&#123;<span class="attr">name</span>:<span class="string">'o3'</span>&#125;</span><br><span class="line"><span class="keyword">var</span> o3 = <span class="built_in">Object</span>.create(P)</span><br></pre></td></tr></table></figure>
<p><strong>Object.create()的执行过程</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">object</span>(<span class="params">o</span>) </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">F</span> (<span class="params"></span>) </span>&#123;&#125; <span class="comment">// 1. 先创建一个临时性的构造函数F</span></span><br><span class="line">  F.prototype = o <span class="comment">//  2. 然后将传入的对象作为这个构造函数的原型（F.prototype指向o）</span></span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> F() <span class="comment">//   3. 最后返回了这个临时类型的一个新实例</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>new()和Object.create()的区别</strong><br>new()和Object.create()都与js的原型和原型链有关。<br>不同的地方在于，<code>创建新对象的先后顺序不一样</code>。new()的思路是<code>先创建对象</code>然后<code>再设置关联关系</code>。Object.create()的思路是<code>先好关联关系</code>然后<code>再创建对象</code>。<br>还有<code>思考的角度不一样</code>，new()从<code>实例的原型</code>去思考<code>A.__proto__ = B.prototype</code>，Object.create从<code>构造函数的原型</code>去思考<code>F.prototype = B</code>。<br>还有，new()还需要用apply的方式把B的内容搞过来。Object.create()不需要再用apply等方式把B的内容搞过来，因为B已经直接赋值给F.prototype</p>
<p>用create的方式使A继承B</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">A</span>(<span class="params">...</span>) </span>&#123;&#125;  A.prototype...</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">B</span>(<span class="params">...</span>) </span>&#123;&#125;  B.prototype...</span><br><span class="line">A.prototype = <span class="built_in">Object</span>.create(B.prototype);</span><br></pre></td></tr></table></figure>
<h5 id="判断类型"><a href="#判断类型" class="headerlink" title="判断类型"></a>判断类型</h5><p><code>typeof A</code>和<code>A instanceof B</code>的区别与联系<br><code>typeof A</code>的意思是返回A对象的数据类型。<code>typeof</code> 一般返回几个结果：<code>number</code>、<code>string</code>、<code>boolean</code>、<code>object</code>、<code>function</code> 和 <code>undefined</code>。<br>注意：typeof null 的结果是<code>object</code><br><code>A instanceof B</code>的意思是判断A对象是不是B类型。他的原理是：判断<code>A.__proto__</code>与<code>B.prototype</code>是否完全相等，如果不相等则在原型链上继续往上找<code>A.__proto__.__proto__</code>直到找到原型链上有和B.prototype相等的对象。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">myInstanceof</span>(<span class="params">left,right</span>)</span>&#123;</span><br><span class="line">  <span class="keyword">while</span>(left)&#123;</span><br><span class="line">    <span class="keyword">if</span>(left.__proto__ === right.prototype)&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">    &#125;</span><br><span class="line">    left=left.__proto__</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> a = [<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>]</span><br><span class="line"><span class="built_in">console</span>.log(myInstanceof(a,<span class="built_in">Array</span>))<span class="comment">//true</span></span><br><span class="line"><span class="built_in">console</span>.log(myInstanceof(a,<span class="built_in">Object</span>))<span class="comment">//true</span></span><br><span class="line"><span class="built_in">console</span>.log(myInstanceof(a,<span class="built_in">String</span>))<span class="comment">//false</span></span><br><span class="line"><span class="built_in">console</span>.log(myInstanceof(a,<span class="built_in">Number</span>))<span class="comment">//false</span></span><br></pre></td></tr></table></figure>
<h5 id="继承重写"><a href="#继承重写" class="headerlink" title="继承重写"></a>继承重写</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> f = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">   <span class="keyword">this</span>.a = <span class="number">1</span>;</span><br><span class="line">   <span class="keyword">this</span>.b = <span class="number">2</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> o = <span class="keyword">new</span> f(); <span class="comment">// o = &#123;a: 1, b: 2&#125;</span></span><br><span class="line">f.prototype.b = <span class="number">3</span>;</span><br><span class="line">f.prototype.c = <span class="number">4</span>;</span><br><span class="line"><span class="comment">// &#123;a:1, b:2&#125; ---&gt; &#123;b:3, c:4&#125; ---&gt; Object.prototype---&gt; null</span></span><br><span class="line"><span class="built_in">console</span>.log(o.a); <span class="comment">// 1</span></span><br><span class="line"><span class="built_in">console</span>.log(o.b); <span class="comment">// 2</span></span><br><span class="line"><span class="built_in">console</span>.log(o.c); <span class="comment">// 4</span></span><br><span class="line"><span class="built_in">console</span>.log(o.d); <span class="comment">// undefined</span></span><br></pre></td></tr></table></figure>
<p>实现继承的几种方式：</p>
<p>（1）原型链继承。在构造函数的的prototype里面增加属性和方法。这样创建出来的实例就有了这些属性和方法。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Animal</span> (<span class="params">name</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.name = name || <span class="string">'Animal'</span>;</span><br><span class="line">  <span class="keyword">this</span>.sleep = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="keyword">this</span>.name + <span class="string">'正在睡觉！'</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">Animal.prototype.eat = <span class="function"><span class="keyword">function</span>(<span class="params">food</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="keyword">this</span>.name + <span class="string">'正在吃：'</span> + food);</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// 这样就生成了一个Animal类，实力化生成对象后，有方法和属性。</span></span><br></pre></td></tr></table></figure>
<p>（2）原型链继承。给构造函数的prototype赋值对象。这样创建出来的实例就有了这个赋值对象的属性和方法。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Cat</span>(<span class="params"></span>)</span>&#123; &#125;</span><br><span class="line">Cat.prototype = <span class="keyword">new</span> Animal();</span><br><span class="line">Cat.prototype.name = <span class="string">'cat'</span>;</span><br><span class="line"><span class="comment">//　Test Code</span></span><br><span class="line"><span class="keyword">var</span> cat = <span class="keyword">new</span> Cat();</span><br><span class="line"><span class="built_in">console</span>.log(cat.name);<span class="comment">//先在Cat.prototype上面找name，找不到name才去Animal.prototype上面找。所以这里是输出cat。如果是先`Cat.prototype.name = 'cat';`再`Cat.prototype = new Animal();`，就会输出Animal，因为prototype被覆盖了。</span></span><br><span class="line"><span class="built_in">console</span>.log(cat.eat(<span class="string">'fish'</span>));</span><br><span class="line"><span class="built_in">console</span>.log(cat.sleep());</span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Animal); <span class="comment">//true</span></span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Cat); <span class="comment">//true</span></span><br></pre></td></tr></table></figure>
<p>特点：基于原型链，创建出来的对象既是父类的实例，也是子类的实例。<br>缺点：构造函数的prototype被覆盖了，一次只能覆盖一个，所以无法实现多继承。</p>
<p>（3）构造函数继承，使用构造函数.call或者apply的方式实现继承。使用父类的构造函数来增强子类实例，等于是复制父类的实例属性给子类（没用到原型）。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Cat</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">  Animal.call(<span class="keyword">this</span>);</span><br><span class="line">  <span class="keyword">this</span>.name = name || <span class="string">'Tom'</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// Test Code</span></span><br><span class="line"><span class="keyword">var</span> cat = <span class="keyword">new</span> Cat();</span><br><span class="line"><span class="built_in">console</span>.log(cat.name);</span><br><span class="line"><span class="built_in">console</span>.log(cat.sleep());</span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Animal); <span class="comment">// false</span></span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Cat); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<p>特点：可以call或者apply多个对象，所以可以实现多继承。<br>缺点：只把父类的属性和方法call或者apply过来，原型链上的没操作。所以只继承了父类实例的属性和方法，没有继承原型上的属性和方法。</p>
<p>（4）实例继承和拷贝继承<br>实例继承：为父类实例添加新特性，作为子类实例返回<br>拷贝继承：拷贝父类元素上的属性和方法<br>上述两个实用性不强，不一一举例。</p>
<p>（5）组合继承：用构造函数call或apply继承属性和方法，用prototype继承父类，并且把prototype.constructor指回来，不然prototype.constructor会指向父类的构造函数。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Cat</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">  Animal.call(<span class="keyword">this</span>);</span><br><span class="line">  <span class="keyword">this</span>.name = name || <span class="string">'Tom'</span>;</span><br><span class="line">&#125;</span><br><span class="line">Cat.prototype = <span class="keyword">new</span> Animal();<span class="comment">//把原型指向Animal</span></span><br><span class="line">Cat.prototype.constructor = Cat;<span class="comment">//把原型的构造函数指回Cat</span></span><br><span class="line"><span class="comment">// Test Code</span></span><br><span class="line"><span class="keyword">var</span> cat = <span class="keyword">new</span> Cat();</span><br><span class="line"><span class="built_in">console</span>.log(cat.name);</span><br><span class="line"><span class="built_in">console</span>.log(cat.sleep());</span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Animal); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Cat); <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<p>特点：可以继承实例属性/方法，也可以继承原型属性/方法<br>缺点：调用了两次父类构造函数，生成了两份实例。一次是Animal.call(this)，另一次是new Animal()。</p>
<p>（6）寄生组合继承：用call或apply的方式<code>继承父类属性和方法</code>，借助中间对象<code>继承父类的prototype</code>，最子类构造函数的prototype指向中间对象的实例</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Cat</span>(<span class="params">name</span>)</span>&#123;</span><br><span class="line">  Animal.call(<span class="keyword">this</span>);</span><br><span class="line">  <span class="keyword">this</span>.name = name || <span class="string">'Tom'</span>;</span><br><span class="line">&#125;</span><br><span class="line">(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  <span class="comment">// 创建一个没有实例方法的类</span></span><br><span class="line">  <span class="keyword">var</span> Super = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line">  Super.prototype = Animal.prototype;</span><br><span class="line">  <span class="comment">//将实例作为子类的原型</span></span><br><span class="line">  Cat.prototype = <span class="keyword">new</span> Super();</span><br><span class="line">&#125;)();</span><br><span class="line"><span class="comment">// Test Code</span></span><br><span class="line"><span class="keyword">var</span> cat = <span class="keyword">new</span> Cat();</span><br><span class="line"><span class="built_in">console</span>.log(cat.name);</span><br><span class="line"><span class="built_in">console</span>.log(cat.sleep());</span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Animal); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Cat); <span class="comment">//true</span></span><br></pre></td></tr></table></figure>
<p>总结：总的来说可以从两个方向去思考，一个是从<code>构造函数的prototype</code>这个方向，另一个是从<code>构造函数call或者apply</code>这个方向<br>（1）用构造函数.call的方式。缺点：只继承属性和方法没继承原型链。<br>（2）<code>直接在构造函数的prototype上面添加属性方法</code>；缺点：构造函数被覆盖，只能单继承。<br>（3）组合，直接覆盖。<code>直接覆盖构造函数的prototype</code>；缺点：实例化两次。<br>（4）组合，借助中间对象。<code>借助中间对象把原型链连接起来。Middle.prototype=Parent.prototype，Child.prototype = new Middle()</code>。</p>
<h3 id="作用域及闭包"><a href="#作用域及闭包" class="headerlink" title="作用域及闭包"></a>作用域及闭包</h3><h4 id="作用域"><a href="#作用域" class="headerlink" title="作用域"></a>作用域</h4><p>JS采用的是词法作用域，也就是静态作用域。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> value = <span class="number">1</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(value);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">bar</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> value = <span class="number">2</span>;</span><br><span class="line">  foo();</span><br><span class="line">&#125;</span><br><span class="line">bar();</span><br></pre></td></tr></table></figure>
<p>输出1</p>
<p>静态作用域<br>执行foo 函数，先从 foo 函数内部查找是否有局部变量 value，如果没有，就根据书写的位置，查找上面一层的代码，也就是 value 等于 1，所以结果会打印 1。</p>
<p>动态作用域<br>执行foo 函数，先从 foo 函数内部查找是否有局部变量 value。如果没有，就从调用函数的作用域，也就是 bar 函数内部查找 value 变量，所以结果会打印 2。</p>
<p>前面我们已经说了，JavaScript采用的是静态作用域，所以这个例子的结果是 1。</p>
<h4 id="闭包官方定义"><a href="#闭包官方定义" class="headerlink" title="闭包官方定义"></a>闭包官方定义</h4><p>一个函数和词法环境的引用捆绑在一起，这样的组合就是闭包（closure）。</p>
<p>闭包是函数和声明该函数的词法环境的组合。换句话说说就是，函数和声明该函数的词法环境。</p>
<p>词法作用域。词法作用域中<code>有效范围</code>，是变量在代码中<code>声明的位置</code>所决定的。嵌套的函数可以访问在其外部声明的变量。</p>
<p>闭包。JavaScript中的函数会形成闭包。 闭包是由<code>函数</code>以及<code>创建该函数的词法环境</code>组合而成。这个环境包含了这个闭包创建时所能访问的<code>所有局部变量</code>。它们共享相同的函数定义，但是保存了不同的词法环境。</p>
<h4 id="我对闭包的理解"><a href="#我对闭包的理解" class="headerlink" title="我对闭包的理解"></a>我对闭包的理解</h4><p>一般存在以下两个特性<br>1、即使创建它的上下文已经销毁，它仍然存在；<br>2、在代码中引入了自由变量；（自由变量是指在函数中使用的，但既不是函数参数又不是函数的局部变量的变量）</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">makeAdder</span>(<span class="params">x</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params">y</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> x + y;</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> add5 = makeAdder(<span class="number">5</span>);</span><br><span class="line"><span class="keyword">var</span> add10 = makeAdder(<span class="number">10</span>);</span><br><span class="line"><span class="built_in">console</span>.log(add5(<span class="number">2</span>));  <span class="comment">// 7</span></span><br><span class="line"><span class="built_in">console</span>.log(add10(<span class="number">2</span>)); <span class="comment">// 12</span></span><br></pre></td></tr></table></figure>
<p>一般情况下闭包都会伴随着几种情况：函数立即执行、高阶函数。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//函数立即执行</span></span><br><span class="line">(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;&#125;)()</span><br><span class="line"><span class="comment">//高阶函数</span></span><br><span class="line"><span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="为什么要用"><a href="#为什么要用" class="headerlink" title="为什么要用"></a>为什么要用</h4><p>减少全局变量。有的函数只需要执行一次，其内部变量无需维护，可以用闭包。那个变量只会存在闭包里面不会跑到全局里面。</p>
<p>结果缓存。例如：有一个计数器，可以获取当前计数值，可以执行+1或者-1。我希望在全局范围内任何地方调用这个计数器得到的结果都是同一个对象，也就是说我再这里调用+1，那个地方获取值就会跟着+1。这个也有点类似单例模式。模拟私有方法，私有变量，只能调用这个闭包环境里面的方法来获取或者修改里面的变量。</p>
<p>使用闭包，实现单例模式。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> Singleton = (<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  <span class="keyword">var</span> instance;</span><br><span class="line">  <span class="keyword">var</span> CreateSingleton = <span class="function"><span class="keyword">function</span> (<span class="params">name</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.name = name;</span><br><span class="line">    <span class="keyword">if</span>(instance) &#123;</span><br><span class="line">      <span class="keyword">return</span> instance;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 打印实例名字</span></span><br><span class="line">    <span class="keyword">this</span>.getName();</span><br><span class="line">    <span class="keyword">return</span> instance = <span class="keyword">this</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 获取实例的名字</span></span><br><span class="line">  CreateSingleton.prototype.getName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="keyword">this</span>.name)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> CreateSingleton;</span><br><span class="line">&#125;)();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 创建实例对象1</span></span><br><span class="line"><span class="keyword">var</span> a = <span class="keyword">new</span> Singleton(<span class="string">'a'</span>);</span><br><span class="line"><span class="comment">// 创建实例对象2</span></span><br><span class="line"><span class="keyword">var</span> b = <span class="keyword">new</span> Singleton(<span class="string">'b'</span>);</span><br><span class="line"><span class="built_in">console</span>.log(a===b);<span class="comment">//true</span></span><br></pre></td></tr></table></figure>
<p>使用闭包，模拟私有方法，全局唯一一个计数器。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> Counter = (<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> privateCounter = <span class="number">0</span>;</span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">changeBy</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">    privateCounter += val;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    increment: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      changeBy(<span class="number">1</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    decrement: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      changeBy(<span class="number">-1</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    value: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="keyword">return</span> privateCounter;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)();</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(Counter.value()); <span class="comment">/* logs 0 */</span></span><br><span class="line">Counter.increment();</span><br><span class="line">Counter.increment();</span><br><span class="line"><span class="built_in">console</span>.log(Counter.value()); <span class="comment">/* logs 2 */</span></span><br><span class="line">Counter.decrement();</span><br><span class="line"><span class="built_in">console</span>.log(Counter.value()); <span class="comment">/* logs 1 */</span></span><br></pre></td></tr></table></figure>
<p>使用闭包，模拟私有方法，创建多个计数器。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> makeCounter = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> privateCounter = <span class="number">0</span>;</span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">changeBy</span>(<span class="params">val</span>) </span>&#123;</span><br><span class="line">    privateCounter += val;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    increment: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      changeBy(<span class="number">1</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    decrement: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      changeBy(<span class="number">-1</span>);</span><br><span class="line">    &#125;,</span><br><span class="line">    value: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">      <span class="keyword">return</span> privateCounter;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> Counter1 = makeCounter();</span><br><span class="line"><span class="keyword">var</span> Counter2 = makeCounter();</span><br><span class="line"><span class="built_in">console</span>.log(Counter1.value()); <span class="comment">/* logs 0 */</span></span><br><span class="line">Counter1.increment();</span><br><span class="line">Counter1.increment();</span><br><span class="line"><span class="built_in">console</span>.log(Counter1.value()); <span class="comment">/* logs 2 */</span></span><br><span class="line">Counter1.decrement();</span><br><span class="line"><span class="built_in">console</span>.log(Counter1.value()); <span class="comment">/* logs 1 */</span></span><br><span class="line"><span class="built_in">console</span>.log(Counter2.value()); <span class="comment">/* logs 0 */</span></span><br></pre></td></tr></table></figure>
<h4 id="如果不想过多的使用闭包可以考虑使用let"><a href="#如果不想过多的使用闭包可以考虑使用let" class="headerlink" title="如果不想过多的使用闭包可以考虑使用let"></a>如果不想过多的使用闭包可以考虑使用let</h4><p>var声明的变量是全局或者整个函数块的，而let,const声明的变量是块级的变量。<br>var声明的变量存在变量提升，let,const不存在。<br>let声明的变量允许重新赋值，const不允许。</p>
<p>第1秒输出1，第2秒输出2。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//使用闭包的方法，让函数立即执行。</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">var</span> i=<span class="number">0</span>;i&lt;<span class="number">5</span>;i++)&#123;</span><br><span class="line">    (<span class="function"><span class="keyword">function</span>(<span class="params">i</span>)</span>&#123;</span><br><span class="line">        setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            <span class="built_in">console</span>.log(i)</span><br><span class="line">        &#125;,<span class="number">1000</span>*i)</span><br><span class="line">    &#125;)(i)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>输出<br>0<br>1<br>2<br>3<br>4</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//使用let块级作用域，让i在块里面有效。</span></span><br><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i=<span class="number">0</span>;i&lt;<span class="number">5</span>;i++)&#123;</span><br><span class="line">  setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(i)<span class="comment">//i是块级作用域在for里面</span></span><br><span class="line">  &#125;,<span class="number">1000</span>*i)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>输出<br>0<br>1<br>2<br>3<br>4</p>
<p>如果let i = 0 改成var i = 0，就会变成<br>输出<br>5<br>5<br>5<br>5<br>5</p>
<h3 id="异步和单线程"><a href="#异步和单线程" class="headerlink" title="异步和单线程"></a>异步和单线程</h3><h4 id="基本理解-1"><a href="#基本理解-1" class="headerlink" title="基本理解"></a>基本理解</h4><p>Event Loop事件运行机制。简单来说，主要从执行栈、宏任务队列、微任务队列三个维度去描述。</p>
<p><code>setTimeout等是宏任务异步代码</code>，<code>promise是同步代码</code>，<code>promise的resolve是微任务异步代码</code>。</p>
<p>执行栈，顺序执行js每一行代码，遇到异步代码则插入到任务队列。特别注意new Promise是同步代码，只不过它的resolve是异步的应该是把它的resolve放入微队列。</p>
<p>优先级，<code>同步代码&gt;异步代码微任务&gt;异步代码宏任务</code>。执行顺序按照优先级从高到低执行，每一级执行完了才能执行下一级。</p>
<p>微任务或者宏任务执行过程如果还有产生新的任务，则继续插入到任务队列后面。微队列有上限1000行。</p>
<h5 id="前置知识"><a href="#前置知识" class="headerlink" title="前置知识"></a>前置知识</h5><p>push(v)修改原数组，插入最后一个位置，返回数组长度。<br>pop()修改原数组，返回最后一个对象。<br>shift()修改原数组，返回第一个对象。<br>unshift(v)修改原数组，插入第一个位置，返回数组长度。</p>
<p>堆（Heap）。unshift在数组头部插入。堆是一种数据结构，是利用完全二叉树维护的一组数据，堆分为两种，一种为最大堆，一种为最小堆，将根节点最大的堆叫做最大堆或大根堆，根节点最小的堆叫做最小堆或小根堆。<code>堆是线性数据结构，相当于一维数组</code>，有唯一后继。</p>
<p>栈（Stack）。push()在数组末尾插入，pop()在数组末尾删除并返回。栈在计算机科学中是限定<code>仅在表尾进行插入或删除操作</code>的线性表。 栈是一种数据结构，它按照<code>后进先出</code>的原则存储数据，先进入的数据被压入栈底，最后的数据在栈顶，需要读数据的时候从栈顶开始弹出数据。栈是只能在某一端插入和删除的特殊线性表。</p>
<p>队列（Queue）。push()在数组末尾插入，shift()在数组头部删除并返回。特殊之处在于它<code>只允许在表的前端（front）进行删除操作，而在表的后端（rear）进行插入操作</code>，和栈一样，队列是一种操作受限制的线性表。进行插入操作的端称为队尾，进行删除操作的端称为队头。队列中没有元素时，称为空队列。队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队，从队列中删除一个队列元素称为出队。因为队列只允许在一端插入，在另一端删除，所以只有最早进入队列的元素才能最先从队列中删除，故队列又称为<code>先进先出</code>（FIFO—first in first out）</p>
<h5 id="任务队列"><a href="#任务队列" class="headerlink" title="任务队列"></a>任务队列</h5><p>在JavaScript中，任务被分为两种，一种宏任务（MacroTask）也叫Task，一种叫微任务（MicroTask）。<br>MacroTask（宏任务）。script全部代码、<code>setTimeout</code>、<code>setInterval</code>、I/O、UI Rendering。<br>MicroTask（微任务）。<code>process.nextTick (Node独有)</code>优先级最高如果同时存在process.nextTick和Promise.rreslove那么会先执行process.nextTick、<code>Promise.reslove</code>、Object.observe、MutationObserver<br>注意new Promise(){console.log(1)}是同步任务。</p>
<h5 id="执行过程"><a href="#执行过程" class="headerlink" title="执行过程"></a>执行过程</h5><p>执行栈每次扫描js代码，只剥离一层，然后<code>优先执行同步的代码，异步的代码分别放入宏队列和微队列</code>。</p>
<p>在执行微队列microtask queue中任务的时候，如果又产生了microtask，那么会继续添加到队列的末尾，也会在这个周期执行，直到microtask queue为空停止。</p>
<p>当然如果你在microtask中不断的产生microtask，那么其他宏任务macrotask就无法执行了，但是这个操作也不是无限的，拿NodeJS中的微任务process.nextTick()来说，它的上限是1000个。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="number">1</span>);</span><br><span class="line">setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">2</span>);</span><br><span class="line">  <span class="built_in">Promise</span>.resolve().then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="number">3</span>)</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">4</span>)</span><br><span class="line">  resolve(<span class="number">5</span>)</span><br><span class="line">&#125;).then(<span class="function">(<span class="params">data</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(data);</span><br><span class="line">&#125;)</span><br><span class="line">setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">6</span>);</span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">7</span>);</span><br></pre></td></tr></table></figure>
<p><strong>开始执行</strong><br>step1<br>mainStack=[console.log(1)]<br>macroQueue=[]<br>microQueue=[]<br>打印结果<br>1</p>
<p>step2<br>mainStack=[setTimeout]<br>macroQueue=[callback1]<br>microQueue=[]<br>打印结果<br>1</p>
<p>step3<br>mainStack=[promise]<br>macroQueue=[callback1]<br>microQueue=[callback2]<br>打印结果<br>1<br>4</p>
<p>step4<br>mainStack=[setTimeout]<br>macroQueue=[callback1,callback3]<br>microQueue=[callback2]<br>打印结果<br>1<br>4</p>
<p>step5<br>mainStack=[console]<br>macroQueue=[callback1,callback3]<br>microQueue=[callback2]<br>打印结果<br>1<br>4<br>7</p>
<p><strong>全局Script代码执行完了，进入下一个步骤，从microtask queue中依次取出任务执行，直到microtask queue队列为空。</strong><br>step6<br>mainStack=[callback2]<br>macroQueue=[callback1,callback3]<br>microQueue=[]<br>打印结果<br>1<br>4<br>7<br>5</p>
<p>step7（这一步执行callback1的时候又遇到了另一个Promise，Promise异步执行完后在microtask queue中又注册了一个callback4回调函数）<br>mainStack=[callback1]<br>macroQueue=[callback3]<br>microQueue=[]<br>打印结果<br>1<br>4<br>7<br>5<br>2</p>
<p>step8<br>mainStack=[promise]<br>macroQueue=[callback3]<br>microQueue=[callback4]<br>打印结果<br>1<br>4<br>7<br>5<br>2</p>
<p>step9<br>mainStack=[callback4]<br>macroQueue=[callback3]<br>microQueue=[]<br>打印结果<br>1<br>4<br>7<br>5<br>2<br>3</p>
<p>step10<br>mainStack=[callback3]<br>macroQueue=[]<br>microQueue=[]<br>打印结果<br>1<br>4<br>7<br>5<br>2<br>3<br>6</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="number">1</span>);</span><br><span class="line">setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">2</span>);</span><br><span class="line">  <span class="built_in">Promise</span>.resolve().then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="number">3</span>)</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">4</span>)</span><br><span class="line">  resolve(<span class="number">5</span>)</span><br><span class="line">&#125;).then(<span class="function">(<span class="params">data</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(data);</span><br><span class="line">  <span class="built_in">Promise</span>.resolve().then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="number">6</span>)</span><br><span class="line">  &#125;).then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="number">7</span>)</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="number">8</span>)</span><br><span class="line">    &#125;, <span class="number">0</span>);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;)</span><br><span class="line">setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">9</span>);</span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">10</span>);</span><br></pre></td></tr></table></figure>
<p>执行结果<br>1<br>4<br>10<br>5<br>6<br>7<br>2<br>3<br>9<br>8</p>
<h2 id="HTML-CSS"><a href="#HTML-CSS" class="headerlink" title="HTML/CSS"></a>HTML/CSS</h2><h3 id="盒模型"><a href="#盒模型" class="headerlink" title="盒模型"></a>盒模型</h3><p>基本概念：标准模型+IE模型<br>标准模型和IE模型的区别。计算content的方法不一样<br>标准模型：content<br>IE模型：content+padding+border<br><img src="standard-model.jpeg"><br><img src="ie-model.jpeg"></p>
<p>CSS如何设置这两种模型<br>box-sizing:content-box  标准模型<br>box-sizing:border-box   IE模型</p>
<h3 id="布局方式"><a href="#布局方式" class="headerlink" title="布局方式"></a>布局方式</h3><h4 id="float"><a href="#float" class="headerlink" title="float"></a>float</h4><p>左边float:left 右边float:right<br>脱离文档流需要清除浮动，兼容性好。<br>去掉高度不能用。</p>
<h4 id="absolute"><a href="#absolute" class="headerlink" title="absolute"></a>absolute</h4><p>父容器绝对定位，左中右都是绝对定位。position:absolute<br>子节点左边left:0 中间left:300 right:300 右边right:0<br>脱离文档流，兼容性好。<br>去掉高度不能用。</p>
<h4 id="flex"><a href="#flex" class="headerlink" title="flex"></a>flex</h4><p>父容器display:flex<br>子节点左边width:300 中间flex:1 右边width:300<br>弹性布局，经常使用在移动端，兼容性不好IE11以上<br>去掉高度可以用。</p>
<h4 id="table"><a href="#table" class="headerlink" title="table"></a>table</h4><p>父容器display:table<br>子节点display:table-cell 左边width:300 右边width:300中间自适应<br>单元格高度同时增高，兼容性好。<br>去掉高度可以用。</p>
<h4 id="grid"><a href="#grid" class="headerlink" title="grid"></a>grid</h4><p>父容器display:grid<br>子节点行列<br>兼容性不好。<br>去掉高度不能用。</p>
<h3 id="渲染机制"><a href="#渲染机制" class="headerlink" title="渲染机制"></a>渲染机制</h3><h4 id="加载过程"><a href="#加载过程" class="headerlink" title="加载过程"></a>加载过程</h4><p>蓝色线代表<code>网络读取</code>，红色线代表<code>执行时间</code>，这俩都是针对脚本的；绿色线代表 <code>HTML 解析</code>。<br><img src="default-defer-async.jpg"><br><img src="default-defer-async.png"></p>
<p>此图告诉我们以下几个要点：</p>
<ul>
<li>defer 和 async 在网络读取（下载）这块儿是一样的，都是和解析HTML同时进行的（异步的）</li>
<li>它俩的差别在于脚本下载完之后何时执行，显然 defer 是最接近我们对于应用脚本加载和执行的要求的</li>
<li>关于 defer，此图未尽之处在于它是按照加载顺序执行脚本的，这一点要善加利用</li>
<li>async 则是一个乱序执行的主，反正对它来说脚本的加载和执行是紧紧挨着的，所以不管你声明的顺序如何，只要它加载完了就会立刻执行</li>
<li>仔细想想，async 对于应用脚本的用处不大，因为它完全不考虑依赖（哪怕是最低级的顺序执行），不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的，最典型的例子：Google Analytics</li>
</ul>
<p>总结来说就是：<br><code>&lt;script src=&quot;script.js&quot;&gt;&lt;/script&gt;</code><br>没有 defer 或 async，浏览器会立即<code>加载js</code>并<code>执行js</code>，会中断<code>渲染HTML</code>。<br><code>&lt;script async src=&quot;script.js&quot;&gt;&lt;/script&gt;</code><br>有 async，<code>加载js</code>和<code>渲染HTML</code>同时进行（或者说异步进行），并且加载js完成后<code>会</code>中断<code>渲染HTML</code>并且<code>立即执行js</code>。<br><code>&lt;script defer src=&quot;myscript.js&quot;&gt;&lt;/script&gt;</code><br>有 defer，<code>加载js</code>和<code>渲染HTML</code>同时进行（或者说一步进行），并且加载js完成后<code>不会</code>中断<code>渲染HTML</code>，等到<code>渲染HTML</code>结束后，在DOMContentLoaded事件触发之前，才<code>执行js</code>，并且时<code>顺序执行</code>的。</p>
<h4 id="渲染过程"><a href="#渲染过程" class="headerlink" title="渲染过程"></a>渲染过程</h4><p>HTML-&gt;DOM Tree<br>CSS-&gt;CSS Tree<br>DOM Tree + CSS Tree =&gt; Layout <-> Render Tree<br>重排会引起重绘，重绘不一定会重排。重排可以避免，重绘无法避免。<br>Reflow重排：增删节点，移动位置，修改css样式宽高，修改字体<br>Repaint重绘：只影响外观，不影响布局，比如修改颜色。<br>注意：table及其内部元素可能需要多次计算才能确定好其在渲染树中节点的属性值，比同等元素要多花两倍时间，这就是我们尽量避免使用table布局页面的原因之一。<br><img src="render-flow.jpeg"></-></p>
<h2 id="综合知识"><a href="#综合知识" class="headerlink" title="综合知识"></a>综合知识</h2><h3 id="this"><a href="#this" class="headerlink" title="this"></a>this</h3><h4 id="基本理解-2"><a href="#基本理解-2" class="headerlink" title="基本理解"></a>基本理解</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> o = &#123;</span><br><span class="line">  a: <span class="number">2</span>,</span><br><span class="line">  m: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.a + <span class="number">1</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="built_in">console</span>.log(o.m()); <span class="comment">// 3</span></span><br><span class="line"><span class="comment">// 当调用 o.m 时，'this' 指向了 o.</span></span><br><span class="line"><span class="keyword">var</span> p = <span class="built_in">Object</span>.create(o);</span><br><span class="line"><span class="comment">// p是一个继承自 o 的对象</span></span><br><span class="line">p.a = <span class="number">4</span>; <span class="comment">// 创建 p 的自身属性 'a'</span></span><br><span class="line"><span class="built_in">console</span>.log(p.m()); <span class="comment">// 5</span></span><br><span class="line"><span class="comment">// 调用 p.m 时，'this' 指向了 p</span></span><br><span class="line"><span class="comment">// 又因为 p 继承了 o 的 m 函数</span></span><br><span class="line"><span class="comment">// 所以，此时的 'this.a' 即 p.a，就是 p 的自身属性 'a'</span></span><br></pre></td></tr></table></figure>
<p>默认绑定：全局环境中，this默认绑定到window。<br>隐式绑定：一般地，被直接对象所包含的函数调用时，也称为方法调用，this隐式绑定到该直接对象。隐式丢失：隐式丢失是指被隐式绑定的函数丢失绑定对象，从而默认绑定到window。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = <span class="function"><span class="params">()</span> =&gt;</span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">1</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>显式绑定：通过call()、apply()、bind()方法把对象绑定到this上，叫做显式绑定。</p>
<p>new绑定：如果函数或者方法调用之前带有关键字new，它就构成构造函数调用。对于this绑定来说，称为new绑定。</p>
<p>【1】构造函数通常不使用return关键字，它们通常初始化新对象，当构造函数的函数体执行完毕时，它会显式返回。在这种情况下，构造函数调用表达式的计算结果就是这个新对象的值。</p>
<p>【2】如果构造函数使用return语句但没有指定返回值，或者返回一个原始值，那么这时将忽略返回值，同时使用这个新对象作为调用结果。</p>
<p>【3】如果构造函数显式地使用return语句返回一个对象，那么调用表达式的值就是这个对象。</p>
<h4 id="this-bind-call-apply"><a href="#this-bind-call-apply" class="headerlink" title="this,bind,call,apply"></a>this,bind,call,apply</h4><p>bind,call,apply的区别<br>相同点：</p>
<ul>
<li>他们都是用来改变对象的上下文。<br>不同点：</li>
<li>bind返回函数不会立即执行，apply和call会立即执行，并且构造函数如果有返回对象也会返回出来。</li>
<li>apply：调用一个对象的一个方法，用另一个对象替换当前对象。例如：B.apply(A, arguments);把B的内容应用到A里面，参数arguments传给A的构造函数。</li>
<li>call：调用一个对象的一个方法，用另一个对象替换当前对象。例如：B.call(A, args1,args2);把B的内容应用到A里面，参数args1，args2传给A的构造函数。</li>
<li>bind除了返回是函数以外，它的参数和call一样。通过bind改变this作用域会返回一个新的函数，这个函数不会马上执行。</li>
</ul>
<p>bind()方法，创建一个新函数，当这个新函数被调用时，bind()的第一个参数将作为它运行时的this，之后的一序列参数将会在传递的实参前传入作为它的参数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Function</span>.prototype.bind2 = <span class="function"><span class="keyword">function</span> (<span class="params">context</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="keyword">this</span> !== <span class="string">"function"</span>) &#123;</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">"Function.prototype.bind - what is trying to be bound is not callable"</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">var</span> self = <span class="keyword">this</span>;</span><br><span class="line">  <span class="keyword">var</span> args = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>, <span class="number">1</span>);<span class="comment">//去掉数组第一个元素，返回新数组。</span></span><br><span class="line">  <span class="keyword">var</span> fNOP = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;&#125;;</span><br><span class="line">  <span class="keyword">var</span> fbound = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    self.apply(<span class="keyword">this</span> <span class="keyword">instanceof</span> self ? <span class="keyword">this</span> : context, args.concat(<span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>)));</span><br><span class="line">  &#125;</span><br><span class="line">  fNOP.prototype = <span class="keyword">this</span>.prototype;</span><br><span class="line">  fbound.prototype = <span class="keyword">new</span> fNOP();</span><br><span class="line">  <span class="keyword">return</span> fbound;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="Ajax"><a href="#Ajax" class="headerlink" title="Ajax"></a>Ajax</h3><p>在ajax发送请求前加上 anyAjaxObj.setRequestHeader(“If-Modified-Since”,”0”)。<br>在ajax发送请求前加上 anyAjaxObj.setRequestHeader(“Cache-Control”,”no-cache”)。//禁用缓存<br>在URL后面加上一个随机数： “fresh=” + Math.random()。//增加随机数<br>在URL后面加上时间戳：”nowtime=” + new Date().getTime()。//增加随机数<br>如果是使用jQuery，直接这样就可以了 $.ajaxSetup({cache:false})。这样页面的所有ajax都会执行这条语句就是不需要保存缓存记录。</p>
<h3 id="ES6"><a href="#ES6" class="headerlink" title="ES6"></a>ES6</h3><h4 id="基本介绍"><a href="#基本介绍" class="headerlink" title="基本介绍"></a>基本介绍</h4><p>promise、async/await、let、const、块级作用域、箭头函数、generator、class<br>ES6在变量的声明和定义方面增加了let、const声明变量，有局部变量的概念，赋值中有比较吸引人的结构赋值，同时ES6对字符串、 数组、正则、对象、函数等拓展了一些方法，如字符串方面的模板字符串、函数方面的默认参数、对象方面属性的简洁表达方式，ES6也 引入了新的数据类型symbol，新的数据结构set和map,symbol可以通过typeof检测出来，为解决异步回调问题，引入了promise和 generator，还有最为吸引人了实现Class和模块，通过Class可以更好的面向对象编程，使用模块加载方便模块化编程，当然考虑到 浏览器兼容性，我们在实际开发中需要使用babel进行编译<br>重要的特性：<br>块级作用域：ES5只有全局作用域和函数作用域，块级作用域的好处是不再需要立即执行的函数表达式，循环体中的闭包不再有问题<br>rest参数：用于获取函数的多余参数，这样就不需要使用arguments对象了，<br>promise:一种异步编程的解决方案，比传统的解决方案回调函数和事件更合理强大<br>模块化：其模块功能主要有两个命令构成，export和import，export命令用于规定模块的对外接口，import命令用于输入其他模块提供的功能</p>
<h4 id="箭头函数"><a href="#箭头函数" class="headerlink" title="箭头函数"></a>箭头函数</h4><p>箭头函数表达式的语法比函数表达式更简洁，并且没有自己的this，arguments，super或new.target。箭头函数表达式更适用于那些本来<code>需要匿名函数的地方</code>，并且它<code>不能用作构造函数</code>。</p>
<p>ES6 增加了箭头函数，基本语法为</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> func = <span class="function"><span class="params">value</span> =&gt;</span> value;</span><br><span class="line"><span class="comment">// 相当于</span></span><br><span class="line"><span class="keyword">let</span> func = <span class="function"><span class="keyword">function</span> (<span class="params">value</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> value;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。<br>箭头函数与普通函数的区别在于：<br>1、箭头函数没有this，所以需要通过查找作用域链来确定this的值，这就意味着<code>如果箭头函数被非箭头函数包含，this绑定的就是最近一层非箭头函数的this</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.age = <span class="number">0</span>;</span><br><span class="line">  setInterval(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">this</span>.age++; <span class="comment">// |this| 正确地指向 p 实例</span></span><br><span class="line">  &#125;, <span class="number">1000</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> p = <span class="keyword">new</span> Person();</span><br></pre></td></tr></table></figure>
<p>2、由于箭头函数没有自己的this指针，通过 call() 或 apply() 方法调用一个函数时，只能传递参数（不能绑定this—译者注），他们的第一个参数会被忽略。（这种现象对于bind方法同样成立—译者注）<br>3、箭头函数不能用作构造器，和 new一起用会抛出错误。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> Foo = <span class="function"><span class="params">()</span> =&gt;</span> &#123;&#125;;</span><br><span class="line"><span class="keyword">var</span> foo = <span class="keyword">new</span> Foo(); <span class="comment">// TypeError: Foo is not a constructor</span></span><br></pre></td></tr></table></figure>
<p>4、箭头函数没有prototype属性。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> Foo = <span class="function"><span class="params">()</span> =&gt;</span> &#123;&#125;;</span><br><span class="line"><span class="built_in">console</span>.log(Foo.prototype); <span class="comment">// undefined</span></span><br></pre></td></tr></table></figure>
<h4 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h4><h5 id="基本介绍-1"><a href="#基本介绍-1" class="headerlink" title="基本介绍"></a>基本介绍</h5><p>没有Promise，可以用回调函数代替。<br>Promise/A+规范</p>
<ul>
<li>Promise有三种状态，等待（pending）、已完成（fulfilled）、已拒绝（rejected）。</li>
<li>promise对象状态改变只有两种可能，从pending改到fulfilled或者从pending改到rejected，只要这两种情况发生，状态就凝固了，不会再改变。<br>promise 必须提供一个 then方法以访问其当前值、终值和据因。promise.then(resolve, reject),resolve 和 reject都是可选参数。如果 resolve 或reject 不是函数，其必须被忽略.<br>then 方法必须返回一个 promise 对象.</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve,reject</span>)</span>&#123;</span><br><span class="line">  resolve(<span class="number">1</span>)</span><br><span class="line">&#125;).then(<span class="function"><span class="keyword">function</span>(<span class="params">res</span>)</span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(res)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<h5 id="手写Promise"><a href="#手写Promise" class="headerlink" title="手写Promise"></a>手写Promise</h5><p>Promise/A+的执行过程</p>
<ol>
<li>Promise接收一个函数executor作为参数，这个函数在new Promise(func)的时候就会被执行。（所以这里也解释了，为什么func里面的代码是同步代码的原因，then才是异步执行的微任务。）</li>
<li>这个函数executor里面有两个参数，一个是用来执行成功的，另一个是用来执行失败的。</li>
<li>Promise里面有三种状态分别是PENDING、FULFILLED、REJECTED，只有PENDING-&gt;FULFILLED和PENDING-&gt;REJECTED两种情况可以赋值。</li>
<li>提供then方法获取Promise里面的value。注意：then是异步的，只有调用了executor里面的resolve或者reject才会执行then里面的方法。</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyPromise</span></span>&#123;</span><br><span class="line">  <span class="keyword">constructor</span>(executor)&#123;</span><br><span class="line">    <span class="keyword">this</span>.status=<span class="string">'pending'</span></span><br><span class="line">    <span class="keyword">this</span>.value=<span class="literal">undefined</span></span><br><span class="line">    <span class="keyword">this</span>.onFulfilledCallbacks=[]</span><br><span class="line">    <span class="keyword">this</span>.onRejectedCallbacks=[]</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">let</span> resolve = <span class="function">(<span class="params">value</span>)=&gt;</span>&#123;</span><br><span class="line">      <span class="keyword">if</span>(<span class="keyword">this</span>.status==<span class="string">'pending'</span>)&#123;<span class="comment">//3. Promise里面有三种状态分别是pending、fulfilled、rejected，只有pending-&gt;fulfilled和pending-&gt;rejected两种情况可以赋值。</span></span><br><span class="line">        <span class="keyword">this</span>.status=<span class="string">'fulfilled'</span></span><br><span class="line">        <span class="keyword">this</span>.value=value</span><br><span class="line">        <span class="keyword">this</span>.onFulfilledCallbacks.forEach(<span class="function"><span class="params">fn</span>=&gt;</span>fn())</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> reject = <span class="function">(<span class="params">value</span>)=&gt;</span>&#123;</span><br><span class="line">      <span class="keyword">if</span>(<span class="keyword">this</span>.status==<span class="string">'pending'</span>)&#123;<span class="comment">//3. Promise里面有三种状态分别是pending、fulfilled、rejected，只有pending-&gt;fulfilled和pending-&gt;rejected两种情况可以赋值。</span></span><br><span class="line">        <span class="keyword">this</span>.status=<span class="string">'rejected'</span></span><br><span class="line">        <span class="keyword">this</span>.value=value</span><br><span class="line">        <span class="keyword">this</span>.onRejectedCallbacks.forEach(<span class="function"><span class="params">fn</span>=&gt;</span>fn())</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 1. Promise接收一个函数作为参数，这个函数在new Promise(func)的时候就会被执行。</span></span><br><span class="line">    <span class="comment">// 2. 这个函数executor里面有两个参数，一个是用来执行成功的，另一个是用来执行失败的。</span></span><br><span class="line">    executor(resolve,reject)</span><br><span class="line">  &#125;</span><br><span class="line">  then(onFulfilled,onRejected)&#123;</span><br><span class="line">    <span class="comment">//这里的判断用来处理当promise状态固化之后，想要再调用p.then的时候。promise执行结束之后的，这个是同步的。</span></span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">this</span>.status==<span class="string">'fulfilled'</span>)&#123;</span><br><span class="line">      onFulfilled(<span class="keyword">this</span>.value)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">this</span>.status==<span class="string">'rejected'</span>)&#123;</span><br><span class="line">      onRejected(<span class="keyword">this</span>.value)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//p.then的那一下并没有执行，而是把函数放到数组里面，等到resolve的时候才执行。所以这个是异步的。</span></span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">this</span>.status==<span class="string">'pending'</span>)&#123;</span><br><span class="line">        <span class="keyword">this</span>.onFulfilledCallbacks.push(<span class="function"><span class="params">()</span>=&gt;</span>&#123;onFulfilled(<span class="keyword">this</span>.value)&#125;)</span><br><span class="line">        <span class="keyword">this</span>.onRejectedCallbacks.push(<span class="function"><span class="params">()</span>=&gt;</span>&#123;onRejected(<span class="keyword">this</span>.value)&#125;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> MyPromise(<span class="function">(<span class="params">resolve,reject</span>)=&gt;</span>&#123;</span><br><span class="line">    setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        resolve(<span class="string">'ok'</span>)</span><br><span class="line">    &#125;,<span class="number">1000</span>)</span><br><span class="line">&#125;)</span><br><span class="line">p.then(<span class="function">(<span class="params">res</span>)=&gt;</span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(res)</span><br><span class="line">&#125;,(err)=&gt;&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(err)</span><br><span class="line">&#125;)</span><br><span class="line">setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    p.then(<span class="function">(<span class="params">res</span>)=&gt;</span>&#123;</span><br><span class="line">      <span class="built_in">console</span>.log(res)</span><br><span class="line">    &#125;,(err)=&gt;&#123;</span><br><span class="line">      <span class="built_in">console</span>.log(err)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;,<span class="number">2000</span>)</span><br></pre></td></tr></table></figure>
<h4 id="Generator"><a href="#Generator" class="headerlink" title="Generator"></a>Generator</h4><p>generator函数使用:<br>1、分段执行，可以暂停<br>2、可以控制阶段和每个阶段的返回值<br>3、可以知道是否执行到结尾</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span>* <span class="title">g</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> o = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">yield</span> o++;</span><br><span class="line">  <span class="keyword">yield</span> o++;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> gen = g();</span><br><span class="line"><span class="built_in">console</span>.log(gen.next()); <span class="comment">// 执行gen的第1个yield，o=2。返回：Object &#123;value: 1, done: false&#125;</span></span><br><span class="line"><span class="keyword">var</span> xxx = g();</span><br><span class="line"><span class="built_in">console</span>.log(gen.next()); <span class="comment">// 执行gen的第2个yield，o=3。返回：Object &#123;value: 2, done: false&#125;</span></span><br><span class="line"><span class="built_in">console</span>.log(xxx.next()); <span class="comment">// 执行xxx的第1个yield，o=2。返回：Object &#123;value: 1, done: false&#125;</span></span><br><span class="line"><span class="built_in">console</span>.log(gen.next()); <span class="comment">// 执行gen的第3个yield，gen里面没有第三个yield，所以返回：Object &#123;value: undefined, done: true&#125;</span></span><br></pre></td></tr></table></figure>
<p>generator和异步控制:<br>利用Generator函数的暂停执行的效果，可以把异步操作写在yield语句里面，等到调用next方法时再往后执行。这实际上等同于不需要写回调函数了，因为异步操作的后续操作可以放在yield语句下面，反正要等到调用next方法时再执行。所以，Generator函数的一个重要实际意义就是用来处理异步操作，改写回调函数。</p>
<h4 id="async-await"><a href="#async-await" class="headerlink" title="async/await"></a>async/await</h4><p>async放在函数上面，在函数里面用await。<br>async 表示这是一个async函数，await只能用在这个函数里面。<br>await 表示在这里等待异步操作返回结果，再继续执行。<br>await 后一般是一个promise对象</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">(<span class="keyword">async</span> () = &gt; &#123;</span><br><span class="line">  <span class="keyword">await</span> <span class="keyword">new</span> promise();</span><br><span class="line">&#125;)()</span><br><span class="line"><span class="comment">// 使用promise.then串行执行。</span></span><br><span class="line">A.then(B).then(C).catch(...)</span><br><span class="line"><span class="comment">// 使用async/await串行执行。</span></span><br><span class="line">(<span class="keyword">async</span> ()=&gt;&#123;</span><br><span class="line"><span class="keyword">await</span> a();</span><br><span class="line"><span class="keyword">await</span> b();</span><br><span class="line"><span class="keyword">await</span> c();</span><br><span class="line">&#125;)()</span><br></pre></td></tr></table></figure>
<p>示例:async用于定义一个异步函数，该函数返回一个Promise。<br>如果async函数返回的是一个同步的值，这个值将被包装成一个理解resolve的Promise，等同于return Promise.resolve(value)。</p>
<p>await用于一个异步操作之前，表示要“等待”这个异步操作的返回值。await也可以用于一个同步的值。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> timer = <span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">timer</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve,reject</span>) =&gt;</span> &#123;</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      resolve(<span class="string">'500'</span>);</span><br><span class="line">    &#125;,<span class="number">500</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line">timer().then(<span class="function"><span class="params">result</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(result);  <span class="comment">//500</span></span><br><span class="line">&#125;).catch(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="built_in">console</span>.log(err.message);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<h3 id="数组"><a href="#数组" class="headerlink" title="数组"></a>数组</h3><h4 id="常用方法"><a href="#常用方法" class="headerlink" title="常用方法"></a>常用方法</h4><p>构造栈：用push入栈、用pop出栈。</p>
<p>构造队列：用unshift入队列，用pop出队列。</p>
<p>测试source tree</p>
<p>在队尾操作：插入push()，返回pop()，<br>在队首操作：插入unshift()，返回shift()，<br>splice()，slice()，sort()，reverse()，map()等</p>
<p>array.slice(start, end)<br><code>不会</code>改变原始数组。从已有的数组中返回选定的元素。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fruits = [<span class="string">"Banana"</span>, <span class="string">"Orange"</span>, <span class="string">"Lemon"</span>, <span class="string">"Apple"</span>, <span class="string">"Mango"</span>];</span><br><span class="line"><span class="keyword">var</span> citrus = fruits.slice(<span class="number">1</span>,<span class="number">3</span>);<span class="comment">// Orange,Lemon</span></span><br></pre></td></tr></table></figure>
<p>array.splice(index, howmany, item1, ….., itemX)<br><code>会</code>改变原始数组。用于添加或删除数组中的元素。如果没有后面的item1,…,itemX就变成简单的删除。从index开始，删除howmany，并且返回删除的元素。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> fruits = [<span class="string">"Banana"</span>, <span class="string">"Orange"</span>, <span class="string">"Apple"</span>, <span class="string">"Mango"</span>];</span><br><span class="line"><span class="keyword">let</span> result = fruits.splice(<span class="number">2</span>,<span class="number">0</span>,<span class="string">"Lemon"</span>,<span class="string">"Kiwi"</span>);</span><br><span class="line"><span class="comment">//从第2个开始，删除0个，并且添加Lemon、Kiwi。</span></span><br><span class="line"><span class="comment">//最后结果是，返回[]，原数组变成["Banana", "Orange", "Lemon", "Kiwi", "Apple", "Mango"]</span></span><br><span class="line"><span class="keyword">let</span> result = fruits.splice(<span class="number">2</span>,<span class="number">1</span>,<span class="string">"Lemon"</span>,<span class="string">"Kiwi"</span>);</span><br><span class="line"><span class="comment">//从第2个开始，删除1个，并且添加Lemon、Kiwi。</span></span><br><span class="line"><span class="comment">//最后结果是，返回["Apple"]，原数组变成["Banana", "Orange", "Lemon", "Kiwi", "Mango"]</span></span><br></pre></td></tr></table></figure>
<p>注意sort排序的时候，会把数字当成字符串来排序，例如10会派在2前面，因为1小于2，所以如果是用在数组的排序上面，就要用function参数。<br>如下：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sort(<span class="function">(<span class="params">a,b</span>)=&gt;</span>&#123;<span class="keyword">return</span> a - b&#125;)</span><br></pre></td></tr></table></figure>
<h4 id="数组去重"><a href="#数组去重" class="headerlink" title="数组去重"></a>数组去重</h4><p>法一：用indexOf循环判断<br>法二：ES6 Set去重；Array.from(new Set(array))<br>法三：Object 键值对去重；把数组的值存成 Object 的 key 值，比如 Object[value1] = true，在判断另一个值的时候，如果 Object[value2]存在的话，就说明该值是重复的。</p>
<h4 id="循环方法的区别"><a href="#循环方法的区别" class="headerlink" title="循环方法的区别"></a>循环方法的区别</h4><p>for-in是ES5标准，遍历的是key（可遍历对象、数组或字符串的key）。for-in总是得到对象的key或数组、字符串的下标。<br>for-of是ES6标准，遍历的是value（可遍历对象、数组或字符串的value）。for-of总是得到对象的value或数组、字符串的值，另外还可以用于遍历Map和Set。</p>
<h3 id="事件代理"><a href="#事件代理" class="headerlink" title="事件代理"></a>事件代理</h3><h4 id="DOM0-事件"><a href="#DOM0-事件" class="headerlink" title="DOM0 事件"></a>DOM0 事件</h4><p>DOM0 事件就是直接通过 onclick 绑定到 html上的事件。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 绑定事件</span></span><br><span class="line">&lt;input onclick=<span class="string">"xx"</span>/&gt;</span><br><span class="line"><span class="comment">// 清除事件</span></span><br><span class="line">input.onclick = <span class="literal">null</span></span><br></pre></td></tr></table></figure>
<h4 id="DOM2-事件"><a href="#DOM2-事件" class="headerlink" title="DOM2 事件"></a>DOM2 事件</h4><p>DOM2 事件是通过 addEventListener 绑定的事件。DOM2级事件有三个参数： 第一个参数是事件名（如click）；第二个参数是事件处理程序函数；第三个参数如果是true则表示在捕获阶段调用，为false表示在冒泡。IE只支持事件冒泡。<br>DOM2 包含3个事件：事件捕获阶段、处于目标阶段和事件冒泡阶段。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 绑定事件</span></span><br><span class="line">input.addEventListener( <span class="string">"click"</span> ,a)</span><br><span class="line"><span class="comment">// 清除事件</span></span><br><span class="line">input.removeEventListener( <span class="string">"click"</span> ,a)</span><br></pre></td></tr></table></figure>
<p>事件代理是利用事件的冒泡原理来实现的。何为事件冒泡呢？就是事件从最深的节点开始，然后逐步向上传播事件。<br>事件捕获由上往下，点击了一个元素，事件传播从上往下。<br>事件冒泡由下往上，点击了一个元素，点击冒泡从下往上。<br>事件代理的好处时：减少内存消耗，节约效率</p>
<p>举个例子：<br>页面上有这么一个节点树，div&gt;ul&gt;li&gt;a；<br>比如给最里面的a加一个click点击事件，那么这个事件就会一层一层的往外执行，执行顺序a&gt;li&gt;ul&gt;div；<br>我们给最外面的div加点击事件，那么里面的ul，li，a做点击事件的时候，都会冒泡到最外层的div上，所以都会触发，这就是事件代理，代理它们父级代为执行事件。<br>event.target，指向触发事件的元素，在事件冒泡过程中这个值不变；<br>event.currentTarget = this，事件绑定的当前元素，只有被点击时目标元素的target才会等于currentTarget；</p>
<p>event.preventDefault，取消该事件（假如事件是可取消的）而不停止事件的进一步传播，<br>event.stopPropagation，阻止捕获和冒泡阶段中，当前事件的进一步传播；<br>event.stopImmediatePropagetion，阻止调用相同事件的其他侦听器：</p>
<h4 id="DOM3事件"><a href="#DOM3事件" class="headerlink" title="DOM3事件"></a>DOM3事件</h4><p>DOM3级事件在DOM2级事件的基础上添加了更多的事件类型，全部类型如下：如：load、scroll、blur、focus等。</p>
<h3 id="拷贝"><a href="#拷贝" class="headerlink" title="拷贝"></a>拷贝</h3><p>浅拷贝和深拷贝的区别。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//浅拷贝</span></span><br><span class="line"><span class="keyword">let</span> a=[<span class="number">0</span>,<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>],</span><br><span class="line">    b=a;</span><br><span class="line"><span class="built_in">console</span>.log(a===b);</span><br><span class="line">a[<span class="number">0</span>]=<span class="number">1</span>;</span><br><span class="line"><span class="built_in">console</span>.log(a,b);</span><br><span class="line"><span class="comment">//a输出[1,1,2,3,4]</span></span><br><span class="line"><span class="comment">//b输出[1,1,2,3,4]</span></span><br><span class="line"><span class="comment">// 这就是浅拷贝，只拷贝了引用，导致a变化引起了b变化。</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> a=[<span class="number">0</span>,<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>]</span><br><span class="line"><span class="keyword">let</span> b=a.slice(<span class="number">0</span>);<span class="comment">//深拷贝，生成一个新数组，与原数组没关系。</span></span><br><span class="line"><span class="built_in">console</span>.log(a===b);</span><br><span class="line">a[<span class="number">0</span>]=<span class="number">1</span>;</span><br><span class="line"><span class="built_in">console</span>.log(a,b);</span><br><span class="line"><span class="comment">// a输出[1,1,2,3,4]</span></span><br><span class="line"><span class="comment">// b输出[0,1,2,3,4]</span></span><br></pre></td></tr></table></figure>
<h4 id="乞丐版"><a href="#乞丐版" class="headerlink" title="乞丐版"></a>乞丐版</h4><p>这种方法的问题没有考虑循环引用，undefined的值复制不了。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> newObj = <span class="built_in">JSON</span>.parse(<span class="built_in">JSON</span>.stringify(oldObj))</span><br></pre></td></tr></table></figure>
<h4 id="基础版本"><a href="#基础版本" class="headerlink" title="基础版本"></a>基础版本</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 浅拷贝</span></span><br><span class="line"><span class="comment">// 创建一个新的对象，遍历需要克隆的对象，将需要克隆对象的属性依次添加到新对象上，返回。</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clone</span>(<span class="params">target</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> cloneTarget = &#123;&#125;;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> target) &#123;</span><br><span class="line">        cloneTarget[key] = target[key];</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> cloneTarget;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// 如果是原始类型，无需继续拷贝，直接返回。</span></span><br><span class="line"><span class="comment">// 如果是引用类型，创建一个新的对象，遍历需要克隆的对象，将需要克隆对象的属性执行深拷贝后依次添加到新对象上。</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clone</span>(<span class="params">target</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> target === <span class="string">'object'</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> cloneTarget = &#123;&#125;;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> target) &#123;</span><br><span class="line">            cloneTarget[key] = clone(target[key]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> cloneTarget;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">const</span> target = &#123;</span><br><span class="line">    field1: <span class="number">1</span>,</span><br><span class="line">    field2: <span class="literal">undefined</span>,</span><br><span class="line">    field3: <span class="string">'ConardLi'</span>,</span><br><span class="line">    field4: &#123;</span><br><span class="line">        child: <span class="string">'child'</span>,</span><br><span class="line">        child2: &#123;</span><br><span class="line">            child2: <span class="string">'child2'</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    field5:[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>]<span class="comment">// 注意：这里出问题了。原来的是数组，拷贝后变成对象了。</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> result = clone(target)</span><br><span class="line"><span class="built_in">console</span>.log(result)</span><br><span class="line"><span class="comment">// &#123;</span></span><br><span class="line"><span class="comment">//   field1: 1</span></span><br><span class="line"><span class="comment">//   field2: undefined</span></span><br><span class="line"><span class="comment">//   field3: "ConardLi"</span></span><br><span class="line"><span class="comment">//   field4: &#123;child: 'child', child2: &#123;…&#125;&#125;</span></span><br><span class="line"><span class="comment">//   field5: &#123;0: 1, 1: 2, 2: 3, 3: 4&#125;// 注意：这里出问题了。原来的是数组，拷贝后变成对象了。</span></span><br><span class="line"><span class="comment">// &#125;</span></span><br></pre></td></tr></table></figure>
<h4 id="考虑数组"><a href="#考虑数组" class="headerlink" title="考虑数组"></a>考虑数组</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clone</span>(<span class="params">target</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> target === <span class="string">'object'</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> cloneTarget = <span class="built_in">Array</span>.isArray(target) ? [] : &#123;&#125;;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> target) &#123;</span><br><span class="line">            cloneTarget[key] = clone(target[key]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> cloneTarget;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// &#123;</span></span><br><span class="line"><span class="comment">//   field1: 1</span></span><br><span class="line"><span class="comment">//   field2: undefined</span></span><br><span class="line"><span class="comment">//   field3: "ConardLi"</span></span><br><span class="line"><span class="comment">//   field4: &#123;child: 'child', child2: &#123;…&#125;&#125;</span></span><br><span class="line"><span class="comment">//   field5: (4) [1, 2, 3, 4]//解决了数组问题。</span></span><br><span class="line"><span class="comment">// &#125;</span></span><br></pre></td></tr></table></figure>
<p>考虑数组还有另外一种写法。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">deepClone</span>(<span class="params">obj</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">var</span> newObj= obj <span class="keyword">instanceof</span> <span class="built_in">Array</span> ? []:&#123;&#125;;</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">var</span> item <span class="keyword">in</span> obj)&#123;</span><br><span class="line">        <span class="keyword">var</span> temple= <span class="keyword">typeof</span> obj[item] == <span class="string">'object'</span> ? deepClone(obj[item]):obj[item];</span><br><span class="line">        newObj[item] = temple;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> newObj;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="循环引用"><a href="#循环引用" class="headerlink" title="循环引用"></a>循环引用</h4><p>上面的拷贝代码如果用这个数据结构去拷贝，将会出现内存溢出的问题。<br>所以我们要对拷贝的方法做一下改造。</p>
<ul>
<li>检查map中有无克隆过的对象</li>
<li>有 - 直接返回</li>
<li>没有 - 将当前对象作为key，克隆对象作为value进行存储</li>
<li>继续克隆</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">clone</span>(<span class="params">target, map = new Map(</span>)) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">typeof</span> target === <span class="string">'object'</span>) &#123;</span><br><span class="line">        <span class="keyword">let</span> cloneTarget = <span class="built_in">Array</span>.isArray(target) ? [] : &#123;&#125;;</span><br><span class="line">        <span class="keyword">if</span> (map.get(target)) &#123;</span><br><span class="line">            <span class="keyword">return</span> map.get(target);</span><br><span class="line">        &#125;</span><br><span class="line">        map.set(target, cloneTarget);</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">const</span> key <span class="keyword">in</span> target) &#123;</span><br><span class="line">            cloneTarget[key] = clone(target[key], map);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> cloneTarget;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> target = &#123;</span><br><span class="line">    field1: <span class="number">1</span>,</span><br><span class="line">    field2: <span class="literal">undefined</span>,</span><br><span class="line">    field3: <span class="string">'ConardLi'</span>,</span><br><span class="line">    field4: &#123;</span><br><span class="line">        child: <span class="string">'child'</span>,</span><br><span class="line">        child2: &#123;</span><br><span class="line">            child2: <span class="string">'child2'</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    field5:[<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>]</span><br><span class="line">&#125;;</span><br><span class="line">target.target = target</span><br><span class="line"><span class="keyword">let</span> result = clone(target)</span><br><span class="line"><span class="built_in">console</span>.log(result)</span><br></pre></td></tr></table></figure>
<h4 id="性能优化"><a href="#性能优化" class="headerlink" title="性能优化"></a>性能优化</h4><p>用WeakMap代替Map。<br>WeakMap 对象是一组键/值对的集合，其中的<code>键是弱引用</code>的。其键必须是对象，而<code>值可以是任意</code>的。<br>在计算机程序设计中，弱引用与强引用相对，是指不能确保其引用的对象不会被垃圾回收器回收的引用。 一个对象若只被弱引用所引用，则被认为是不可访问（或弱可访问）的，并因此可能在任何时刻被回收。<br>我们默认创建一个对象：const obj = {}，就默认创建了一个强引用的对象，我们只有手动将obj = null，它才会被垃圾回收机制进行回收，如果是弱引用对象，垃圾回收机制会自动帮我们回收。</p>
<p>如果我们使用Map的话，那么对象间是存在强引用关系的：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123; <span class="attr">name</span> : <span class="string">'ConardLi'</span>&#125;</span><br><span class="line"><span class="keyword">const</span> target = <span class="keyword">new</span> <span class="built_in">Map</span>();</span><br><span class="line">target.set(obj,<span class="string">'code秘密花园'</span>);</span><br><span class="line">obj = <span class="literal">null</span>;</span><br></pre></td></tr></table></figure>
<p>虽然我们手动将obj，进行释放，然是target依然对obj存在强引用关系，所以这部分内存依然无法被释放。<br>而如果是WeakMap的话，target和obj存在的就是弱引用关系，当下一次垃圾回收机制执行时，这块内存就会被释放掉。</p>
<h3 id="数据类型"><a href="#数据类型" class="headerlink" title="数据类型"></a>数据类型</h3><h4 id="基本介绍-2"><a href="#基本介绍-2" class="headerlink" title="基本介绍"></a>基本介绍</h4><p>js的数据类型分为原始类型和对象类型</p>
<p>原始类型，在ECMAScript标准中，它们被定义为primitive values，即原始值，代表值本身是不可被改变的。<br>Null：只包含一个值：null<br>Undefined：只包含一个值：undefined<br>Boolean：包含两个值：true和false<br>Number：整数或浮点数，还有一些特殊值（-Infinity、+Infinity、NaN）<br>String：一串表示文本值的字符序列<br>Symbol：一种实例是唯一且不可改变的数据类型<br>(在es10中加入了第七种原始类型BigInt，现已被最新Chrome支持)</p>
<p>对象类型<br>Object：自己分一类丝毫不过分，除了常用的Object，Array、Function等都属于特殊的对象</p>
<h4 id="赋值"><a href="#赋值" class="headerlink" title="赋值"></a>赋值</h4><p>以字符串为例，我们在调用操作字符串的方法时，没有任何方法是可以直接改变字符串的</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> str = <span class="string">'ConardLi'</span>;</span><br><span class="line">str.slice(<span class="number">1</span>);</span><br><span class="line">str.substr(<span class="number">1</span>);</span><br><span class="line">str.trim(<span class="number">1</span>);</span><br><span class="line">str.toLowerCase(<span class="number">1</span>);</span><br><span class="line">str[<span class="number">0</span>] = <span class="number">1</span>;</span><br><span class="line"><span class="built_in">console</span>.log(str);  <span class="comment">// ConardLi</span></span><br></pre></td></tr></table></figure>
<p>在上面的代码中我们对str调用了几个方法，无一例外，这些方法都在原字符串的基础上产生了一个新字符串，而非直接去改变str，这就印证了字符串的不可变性。<br>那么，当我们继续调用下面的代码：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">str += <span class="string">'6'</span></span><br><span class="line"><span class="built_in">console</span>.log(str);  <span class="comment">// ConardLi6</span></span><br></pre></td></tr></table></figure>
<p>你会发现，str的值被改变了，这不就打脸了字符串的不可变性么？其实不然，我们从内存上来理解：<br>在JavaScript中，每一个变量在内存中都需要一个空间来存储。<br>内存空间又被分为两种，<code>栈内存</code>与<code>堆内存</code>。</p>
<h4 id="栈和堆"><a href="#栈和堆" class="headerlink" title="栈和堆"></a>栈和堆</h4><p>原始数据放在栈内存。JavaScript中的<code>原始类型的值被直接存储在栈中</code>，在变量定义时，栈就为其分配好了内存空间。由于栈中的内存空间的大小是固定的，那么注定了存储在栈中的变量就是不可变的。在上面的代码中，我们执行了str += ‘6’的操作，实际上是在栈中又开辟了一块内存空间用于存储’ConardLi6’，然后将变量str指向这块空间，所以这并不违背不可变性的特点。<br>栈内存：</p>
<ul>
<li>存储的值大小固定</li>
<li>空间较小</li>
<li>可以直接操作其保存的变量，运行效率高</li>
<li>由系统自动分配存储空间</li>
</ul>
<p><img src="storage-in-stack.jpg"><br><img src="storage-in-stack-add.jpg"></p>
<p>引用类型放在堆内存。相对于上面具有不可变性的原始类型，我习惯把对象称为引用类型，引用类型的值实际存储在堆内存中，它<code>在栈中只存储了一个固定长度的地址</code>，这个<code>地址指向堆内存中的值</code>。<br>由于内存是有限的，这些变量不可能一直在内存中占用资源，JS会进行垃圾回收。引用类型可以轻易的被修改。<br>堆内存：</p>
<ul>
<li>存储的值大小不定，可动态调整</li>
<li>空间较大，运行效率低</li>
<li>无法直接操作其内部存储，使用引用地址读取</li>
<li>通过代码进行分配空间</li>
</ul>
<p><img src="storage-in-heap.jpg"></p>
<h4 id="比较"><a href="#比较" class="headerlink" title="比较"></a>比较</h4><p>两种数据类型的比较也是不相同的<br>对于原始类型，比较时会直接比较它们的值，如果值相等，即返回true。<br>对于引用类型，比较时会比较它们的引用地址，虽然两个变量在堆中存储的对象具有的属性值都是相等的，但是它们被存储在了不同的存储空间，因此比较值为false。</p>
<p>如果是浅拷贝，他们在栈存储的地址一样，这样指向的内容也一样，所以这样对比就是true<br><img src="copy-in-heap.jpg"><br><img src="copy-in-stack.jpg"><br>如果是深拷贝，他们在栈存储的地址不一样，虽然指向的内容一样，但是本质上这是两个对象只不过内容一样而已，这样对比就是false<br><img src="value-comparison.jpg"></p>
<p>这就是深拷贝和浅拷贝，造成的影响。</p>
<h4 id="Symbol"><a href="#Symbol" class="headerlink" title="Symbol"></a>Symbol</h4><p>可以作为属性名。由于每一个 Symbol 的值都是不相等的，所以 Symbol 作为对象的属性名，可以保证属性不重名。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> sy = <span class="built_in">Symbol</span>(<span class="string">"key1"</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 写法1</span></span><br><span class="line"><span class="keyword">let</span> syObject = &#123;&#125;;</span><br><span class="line">syObject[sy] = <span class="string">"kk"</span>;</span><br><span class="line"><span class="built_in">console</span>.log(syObject);    <span class="comment">// &#123;Symbol(key1): "kk"&#125;</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// 写法2</span></span><br><span class="line"><span class="keyword">let</span> syObject = &#123;</span><br><span class="line">  [sy]: <span class="string">"kk"</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="built_in">console</span>.log(syObject);    <span class="comment">// &#123;Symbol(key1): "kk"&#125;</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// 写法3</span></span><br><span class="line"><span class="keyword">let</span> syObject = &#123;&#125;;</span><br><span class="line"><span class="built_in">Object</span>.defineProperty(syObject, sy, &#123;<span class="attr">value</span>: <span class="string">"kk"</span>&#125;);</span><br><span class="line"><span class="built_in">console</span>.log(syObject);   <span class="comment">// &#123;Symbol(key1): "kk"&#125;</span></span><br></pre></td></tr></table></figure>
<p>Symbol 作为对象属性名时不能用.运算符，要用方括号。因为.运算符后面是字符串，所以取到的是字符串 sy 属性，而不是 Symbol 值 sy 属性。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> syObject = &#123;&#125;;</span><br><span class="line">syObject[sy] = <span class="string">"kk"</span>;</span><br><span class="line"> </span><br><span class="line">syObject[sy];  <span class="comment">// "kk"</span></span><br><span class="line">syObject.sy;   <span class="comment">// undefined</span></span><br></pre></td></tr></table></figure>
<p>使用 Symbol 定义常量，这样就可以保证这一组常量的值都不相等。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> COLOR_RED = <span class="built_in">Symbol</span>(<span class="string">"red"</span>);</span><br><span class="line"><span class="keyword">const</span> COLOR_YELLOW = <span class="built_in">Symbol</span>(<span class="string">"yellow"</span>);</span><br><span class="line"><span class="keyword">const</span> COLOR_BLUE = <span class="built_in">Symbol</span>(<span class="string">"blue"</span>);</span><br></pre></td></tr></table></figure>
<h4 id="NaN"><a href="#NaN" class="headerlink" title="NaN"></a>NaN</h4><p>NaN是JS中的特殊值，表示非数字。NaN不是数字，但是他的数据类型是数字。<br><code>它不等于任何值，包括自身。</code>NaN == NaN和NaN === NaN 都是false。nudefined === null 返回false。<br>在布尔运算时被当做false，NaN与任何数运算得到的结果都是NaN，当运算失败或者运算无法返回正确的数值的就会返回NaN，一些数学函数的运算结果也会出现NaN</p>
<h4 id="undefined-和-null"><a href="#undefined-和-null" class="headerlink" title="undefined 和 null"></a>undefined 和 null</h4><p>undefined与null：目前null和undefined基本是同义的，只有一些细微的差别，null表示没有对象，undefined表示缺少值，就是此处应该有一个值但是还没有定义。<br>undefined===null返回false，===发现两个类型不一致直接不比较了返回false<br>null == undefined 会返回 true</p>
<h4 id="和"><a href="#和" class="headerlink" title="== 和 ==="></a>== 和 ===</h4><p>在做 == 比较时。不同类型的数据会先转换成一致后在做比较。<br>=== 中如果类型不一致就直接返回false，一致的才会比较。</p>
<h4 id="判断类型-1"><a href="#判断类型-1" class="headerlink" title="判断类型"></a>判断类型</h4><p>Object.prototype.toString.call()<br><code>typeof A</code>的意思是返回A对象的数据类型。<code>typeof</code> 一般返回几个结果：<code>number</code>、<code>string</code>、<code>boolean</code>、<code>object</code>、<code>function</code> 和 <code>undefined</code>。<br>注意：typeof null 的结果是<code>object</code><br><code>A instanceof B</code>的意思是判断A对象是不是B类型。他的原理是：判断<code>A.__proto__</code>与<code>B.prototype</code>是否完全相等，如果不相等则在原型链上继续往上找<code>A.__proto__.__proto__</code>直到找到原型链上有和B.prototype相等的对象。</p>
<p>typeof没办法判断array，用typeof去判断数组返回的是object。判断一个对象是不是数组要用instanceof，在实例的原型链上查找是否有Array的原型。或者也可以用Object.prototype.call.toString()来判断数组的类型。<br>如果一定要用typeof，那么可以按照以下步骤进行：</p>
<ul>
<li>首先判断是否为null；</li>
<li>之后用typeof判断；</li>
<li>如果是object的话，再用array.isarray判断是否为数组；</li>
<li>如果是number的话用isNaN判断是否是NaN即可。</li>
</ul>
<h3 id="defineProperty"><a href="#defineProperty" class="headerlink" title="defineProperty"></a>defineProperty</h3><p>对象里目前存在的属性描述符有两种主要形式：<code>数据描述符</code>和<code>存取描述符</code>。<br>数据描述符是一个具有值的属性，该值可以是<code>可写</code>的，也可以是<code>不可写</code>的。<br>存取描述符是由 getter 函数和 setter 函数所描述的属性。<br>一个描述符只能是这两者其中之一；不能同时是两者。</p>
<h4 id="数据描述符和存取描述符共有的配置"><a href="#数据描述符和存取描述符共有的配置" class="headerlink" title="数据描述符和存取描述符共有的配置"></a>数据描述符和存取描述符共有的配置</h4><p>configurable<br>当且仅当该属性的 configurable 键值为 true 时，该属性的描述符才能够被<code>改变</code>，同时该属性也能从对应的对象上被<code>删除</code>。<br>默认为 false。</p>
<p>enumerable<br>当且仅当该属性的 enumerable 键值为 true 时，该属性才会出现在对象的<code>枚举</code>属性中。<br>默认为 false。</p>
<h4 id="数据描述符特有的配置"><a href="#数据描述符特有的配置" class="headerlink" title="数据描述符特有的配置"></a>数据描述符特有的配置</h4><p>value<br>该属性对应的值。可以是任何有效的 JavaScript <code>值</code>（数值，对象，函数等）。<br>默认为 undefined。</p>
<p>writable<br>当且仅当该属性的 writable 键值为 true 时，属性的值，也就是上面的 value，才能被<code>赋值</code>运算符 (en-US)改变。<br>默认为 false。</p>
<h4 id="存取描述符特有的配置"><a href="#存取描述符特有的配置" class="headerlink" title="存取描述符特有的配置"></a>存取描述符特有的配置</h4><p>get<br>属性的 getter 函数，如果没有 getter，则为 undefined。当访问该属性时，会调用此函数。执行时不传入任何参数，但是会传入 this 对象（由于继承关系，这里的this并不一定是定义该属性的对象）。该函数的<code>返回值</code>会被用作属性的值。<br>默认为 undefined。</p>
<p>set<br>属性的 setter 函数，如果没有 setter，则为 undefined。当属性值被修改时，会调用此函数。该方法接受一个参数（也就是被赋予的新值），会传入赋值时的 this 对象。<br>默认为 undefined。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// (1)通过defineProperty来实现</span></span><br><span class="line"><span class="comment">// Object.defineProperty() 方法会直接在一个对象上定义一个新属性，或者修改一个对象的现有属性，并返回此对象。</span></span><br><span class="line"><span class="comment">// 默认情况下，使用 Object.defineProperty() 添加的属性值是不可修改（immutable）的。</span></span><br><span class="line">obj=&#123;</span><br><span class="line">  name:<span class="string">'大大白'</span>,</span><br><span class="line">  getName:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">this</span>.name</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">object.defineProperty(obj,<span class="string">"name"</span>,&#123;</span><br><span class="line"><span class="comment">//不可枚举不可配置</span></span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">// (2)通过函数的创建形式。用函数闭包实现私有变量。</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">product</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  <span class="keyword">var</span> name=<span class="string">'大大白'</span>;</span><br><span class="line">  <span class="keyword">this</span>.getName=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> name;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> obj=<span class="keyword">new</span> product();</span><br></pre></td></tr></table></figure>
<h4 id="实际应用-1"><a href="#实际应用-1" class="headerlink" title="实际应用"></a>实际应用</h4><p>(1)在ES5中可以通过Object.defineProperty来实现已有属性的监听</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Object</span>.defineProperty(user,<span class="string">'name'</span>,&#123;</span><br><span class="line">  <span class="keyword">set</span>：function(key,value)&#123;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>缺点：如果id不在user对象中，则不能监听id的变化</p>
<p>(2)在ES6中可以通过Proxy来实现</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span>  user = <span class="keyword">new</span> <span class="built_in">Proxy</span>(&#123;&#125;，&#123;</span><br><span class="line">  <span class="keyword">set</span>：function(target,key,value,receiver)&#123;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>这样即使有属性在user中不存在，通过user.id来定义也同样可以这样监听这个属性的变化哦~</p>
<h3 id="resuestAnimationFrame"><a href="#resuestAnimationFrame" class="headerlink" title="resuestAnimationFrame"></a>resuestAnimationFrame</h3><p>（1）requestAnimationFrame会把每一帧中的所有DOM操作<code>集中起来</code>，在<code>一次重绘或回流中就完成</code>，并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。<br>（2）在<code>隐藏或不可见的元素</code>中，requestAnimationFrame将<code>不会进行重绘或回流</code>，这当然就意味着更少的CPU、GPU和内存使用量<br>（3）requestAnimationFrame是<code>由浏览器专门为动画提供的API</code>，在运行时浏览器会<code>自动优化方法的调用</code>，并且如果页面<code>不是激活状态下</code>的话，动画会<code>自动暂停</code>，有效节省了CPU开销。</p>
<h3 id="setTimeout和setInterval"><a href="#setTimeout和setInterval" class="headerlink" title="setTimeout和setInterval"></a>setTimeout和setInterval</h3><h4 id="setTimeout"><a href="#setTimeout" class="headerlink" title="setTimeout"></a>setTimeout</h4><p>setTimeout() 是属于 window 的方法，该方法用于在指定的毫秒数后调用函数或计算表达式。</p>
<p>语法：<br>setTimeout(要执行的代码, 等待的毫秒数)<br>setTimeout(JavaScript 函数, 等待的毫秒数)</p>
<p>参数：<br>code：必需。要调用的函数后要执行的 JavaScript 代码串。<br>millisec： 必需。在执行代码前需等待的毫秒数。</p>
<p>注意：<br>setTimeout() 只执行 code 一次。如果要多次调用，请使用 setInterval() 或者让 code 自身再次调用 setTimeout()。</p>
<h4 id="setInterval"><a href="#setInterval" class="headerlink" title="setInterval"></a>setInterval</h4><p>setInterval() 方法可按照指定的周期（以毫秒计）来调用函数或计算表达式。setInterval() 方法会不停地调用函数，直到 clearInterval() 被调用或窗口被关闭。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。</p>
<p>语法：<br>setInterval(code, milliseconds);<br>setInterval(function, milliseconds, param1, param2, …)</p>
<p>参数：<br>code/function：必需。要调用一个代码串，也可以是一个函数。<br>milliseconds：必须。周期性执行或调用 code/function 之间的时间间隔，以毫秒计。<br>param1, param2：可选。 传给执行函数的其他参数（IE9 及其更早版本不支持该参数）。</p>
<p>注意：<br>返回一个 ID（数字），可以将这个ID传递给clearInterval()，clearTimeout() 以取消执行。</p>
<h3 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h3><h4 id="原型和原型链-1"><a href="#原型和原型链-1" class="headerlink" title="原型和原型链"></a>原型和原型链</h4><p><code>a.__proto__ = A.prototype</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Function</span>.prototype.a = <span class="number">1</span>;</span><br><span class="line"><span class="built_in">Object</span>.prototype.b = <span class="number">2</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">A</span>(<span class="params"></span>) </span>&#123;&#125;</span><br><span class="line"><span class="keyword">var</span> a = <span class="keyword">new</span> A();</span><br><span class="line"><span class="built_in">console</span>.log(a.a, a.b); <span class="comment">// undefined, 2</span></span><br><span class="line"><span class="built_in">console</span>.log(A.a, A.b); <span class="comment">// 1, 2</span></span><br></pre></td></tr></table></figure>
<h4 id="箭头函数this指向"><a href="#箭头函数this指向" class="headerlink" title="箭头函数this指向"></a>箭头函数this指向</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> a=<span class="number">11</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">test2</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  <span class="keyword">this</span>.a=<span class="number">22</span>;</span><br><span class="line">  <span class="keyword">let</span> b=<span class="function"><span class="params">()</span>=&gt;</span>&#123;<span class="built_in">console</span>.log(<span class="keyword">this</span>.a)&#125;</span><br><span class="line">  b();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> x=<span class="keyword">new</span> test2();</span><br></pre></td></tr></table></figure>
<p>输出22，如果<code>let b=()=&gt;{console.log(a)}</code>，则输出11。</p>
<h4 id="EventLoop"><a href="#EventLoop" class="headerlink" title="EventLoop"></a>EventLoop</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;<span class="built_in">console</span>.log(<span class="number">1</span>)&#125;,<span class="number">0</span>);</span><br><span class="line"><span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve,reject</span>)</span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="number">2</span>);</span><br><span class="line">  resolve();</span><br><span class="line">&#125;).then(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;<span class="built_in">console</span>.log(<span class="number">3</span>)</span><br><span class="line">&#125;).then(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;<span class="built_in">console</span>.log(<span class="number">4</span>)&#125;);</span><br><span class="line">process.nextTick(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;<span class="built_in">console</span>.log(<span class="number">5</span>)&#125;);</span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">6</span>);</span><br></pre></td></tr></table></figure>
<p>运行结果：<br>2<br>6<br>3<br>4<br>5<br>1</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="number">1</span>)</span><br><span class="line">&#125;, <span class="number">0</span>);</span><br><span class="line"><span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve, reject</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="number">2</span>)</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; <span class="number">10000</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">if</span>(i === <span class="number">10</span>) &#123;<span class="built_in">console</span>.log(<span class="number">10</span>)&#125;</span><br><span class="line">        i == <span class="number">9999</span> &amp;&amp; resolve();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="number">3</span>)</span><br><span class="line">&#125;).then(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="number">4</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">console</span>.log(<span class="number">5</span>);</span><br></pre></td></tr></table></figure>
<p>运行结果：<br>2<br>10<br>3<br>5<br>4<br>1</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="keyword">var</span> i=<span class="number">0</span>;i&lt;<span class="number">5</span>;i++) &#123; </span><br><span class="line">  setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123; </span><br><span class="line">    <span class="built_in">console</span>.log(i); </span><br><span class="line">  &#125;,<span class="number">1000</span>); </span><br><span class="line">&#125; </span><br><span class="line"><span class="built_in">console</span>.log(i)</span><br></pre></td></tr></table></figure>
<p>运行结果：先打出一个5，再打出五个5。<br>for是同步代码，会执行五次循环，i等于5，最后一行是同步任务先打出5，然后setTimeout是异步任务宏任务，会等其他同步任务和微任务执行完后再执行。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="keyword">let</span> i=<span class="number">0</span>;i&lt;<span class="number">5</span>;i++) &#123; </span><br><span class="line">  setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123; </span><br><span class="line">    <span class="built_in">console</span>.log(i); </span><br><span class="line">  &#125;,<span class="number">1000</span>); </span><br><span class="line">&#125; </span><br><span class="line"><span class="built_in">console</span>.log(i)</span><br><span class="line"><span class="comment">// 输出以下结果：</span></span><br><span class="line"><span class="comment">// 5</span></span><br><span class="line"><span class="comment">// 0</span></span><br><span class="line"><span class="comment">// 1</span></span><br><span class="line"><span class="comment">// 2</span></span><br><span class="line"><span class="comment">// 3</span></span><br><span class="line"><span class="comment">// 4</span></span><br></pre></td></tr></table></figure>
<p>for是同步代码，会执行五次循环，但是i是用let定义，let定义的i是块级作用域，他在每个循环里面单独存在，所以i在每次循环数值都不一样。<br>最后一行是同步任务先打出i的最后结果5，然后setTimeout是异步任务宏任务，会等1秒后，再打出01234</p>
<h4 id="下划线命名到驼峰命名"><a href="#下划线命名到驼峰命名" class="headerlink" title="下划线命名到驼峰命名"></a>下划线命名到驼峰命名</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 用replace函数，匹配到下划线开头的字符，把首字符调大写。</span></span><br><span class="line"><span class="comment">// 下划线转换驼峰</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">toHump</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> name.replace(<span class="regexp">/\_(\w)/g</span>, <span class="function"><span class="keyword">function</span>(<span class="params">all, letter</span>)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> letter.toUpperCase();</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 用replace函数，匹配到大写字符，把大写字符在前面加下划线，然后全部转换成小写字母</span></span><br><span class="line"><span class="comment">// 驼峰转换下划线</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">toLine</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> name.replace(<span class="regexp">/([A-Z])/g</span>,<span class="string">"_$1"</span>).toLowerCase();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="防抖和节流"><a href="#防抖和节流" class="headerlink" title="防抖和节流"></a>防抖和节流</h4><p>问题：在拖动滚动条的时候，执行函数showTop，会发现稍微滚动一下，就会执行好多次showTop。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">showTop</span>  (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> scrollTop = <span class="built_in">document</span>.body.scrollTop || <span class="built_in">document</span>.documentElement.scrollTop;</span><br><span class="line">　　<span class="built_in">console</span>.log(<span class="string">'滚动条位置：'</span> + scrollTop);</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">window</span>.onscroll = showTop<span class="comment">// 如果不增加防抖，那么每拖动一下，都会执行好多次showTop</span></span><br><span class="line"><span class="built_in">window</span>.onscroll = debounce(showTop,<span class="number">1000</span>)<span class="comment">// 加入防抖，1s内无论执行多少次，都会等到1s后才执行一次。只要onscroll还在执行就永远不会触发shoTop，也就是说只要一直在拖动就永远不会触发showTop。</span></span><br><span class="line"><span class="built_in">window</span>.onscroll = throttle(showTop,<span class="number">1000</span>) <span class="comment">// 假如节流，</span></span><br></pre></td></tr></table></figure>
<p>防抖：如果短时间内大量触发同一事件，<code>事件停止后1000ms，执行一次函数</code>，如果事件不停止就一直不触发。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*</span></span><br><span class="line"><span class="comment">* fn [function] 需要防抖的函数</span></span><br><span class="line"><span class="comment">* delay [number] 毫秒，防抖期限值</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">debounce</span>(<span class="params">fn,delay</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> timer = <span class="literal">null</span> <span class="comment">//借助闭包</span></span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(timer)&#123;</span><br><span class="line">            clearTimeout(timer) <span class="comment">//进入该分支语句，说明当前正在一个计时过程中，并且又触发了相同事件。所以要取消当前的计时，重新开始计时</span></span><br><span class="line">            timer = setTimeout(fn,delay) </span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            timer = setTimeout(fn,delay) <span class="comment">// 进入该分支说明当前并没有在计时，那么就开始一个计时</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>节流：如果短时间内大量触发同一事件，<code>事件开始后1000ms，只执行一次函数</code>，无论事件停不停止，只要事件开始1000ms后就会触发。如果事件持续不停止也是会等到下一个1000ms才会再次触发。与事件停不停止没关系。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">throttle</span>(<span class="params">fn,delay</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> valid = <span class="literal">true</span></span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">       <span class="keyword">if</span>(!valid)&#123;</span><br><span class="line">           <span class="comment">//休息时间 暂不接客</span></span><br><span class="line">           <span class="keyword">return</span> <span class="literal">false</span> </span><br><span class="line">       &#125;</span><br><span class="line">       <span class="comment">// 工作时间，执行函数并且在间隔期内把状态位设为无效</span></span><br><span class="line">        valid = <span class="literal">false</span></span><br><span class="line">        setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            fn()</span><br><span class="line">            valid = <span class="literal">true</span>;</span><br><span class="line">        &#125;, delay)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="将原生ajax封装到Promise"><a href="#将原生ajax封装到Promise" class="headerlink" title="将原生ajax封装到Promise"></a>将原生ajax封装到Promise</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span>  myNewAjax=<span class="function"><span class="keyword">function</span>(<span class="params">url</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="keyword">function</span>(<span class="params">resolve,reject</span>)</span>&#123;</span><br><span class="line">        <span class="keyword">var</span> xhr = <span class="keyword">new</span> XMLHttpRequest();</span><br><span class="line">        xhr.open(<span class="string">'get'</span>,url);</span><br><span class="line">        xhr.send(data);</span><br><span class="line">        xhr.onreadystatechange=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            <span class="keyword">if</span>(xhr.status==<span class="number">200</span>&amp;&amp;readyState==<span class="number">4</span>)&#123;</span><br><span class="line">                <span class="keyword">var</span> json=<span class="built_in">JSON</span>.parse(xhr.responseText);</span><br><span class="line">                resolve(json)</span><br><span class="line">            &#125;<span class="keyword">else</span> <span class="keyword">if</span>(xhr.readyState==<span class="number">4</span>&amp;&amp;xhr.status!=<span class="number">200</span>)&#123;</span><br><span class="line">                reject(<span class="string">'error'</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="实现sleep"><a href="#实现sleep" class="headerlink" title="实现sleep"></a>实现sleep</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve,reject</span>)=&gt;</span>&#123;</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span>=&gt;</span>resolve(<span class="number">111</span>),<span class="number">1000</span>)</span><br><span class="line">&#125;)</span><br><span class="line">p.then(<span class="function"><span class="params">res</span>=&gt;</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(res)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<h4 id="实现bind"><a href="#实现bind" class="headerlink" title="实现bind"></a>实现bind</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Function</span>.prototype.bind=<span class="function"><span class="keyword">function</span>(<span class="params">obj,arg</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">var</span> arg=<span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>,<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">var</span> context=<span class="keyword">this</span>;</span><br><span class="line">    <span class="keyword">var</span> bound=<span class="function"><span class="keyword">function</span>(<span class="params">newArg</span>)</span>&#123;</span><br><span class="line">        arg=arg.concat(<span class="built_in">Array</span>.prototype.slice.call(newArg));</span><br><span class="line">        <span class="keyword">return</span> context.apply(obj,arg);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//寄生组合集成，把原型链接上。</span></span><br><span class="line">    <span class="keyword">var</span> F=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;&#125;</span><br><span class="line">    F.prototype=context.prototype;</span><br><span class="line">    bound.prototype=<span class="keyword">new</span> F();</span><br><span class="line">    <span class="keyword">return</span> bound;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="场景"><a href="#场景" class="headerlink" title="场景"></a>场景</h3><h4 id="计算一年多少周"><a href="#计算一年多少周" class="headerlink" title="计算一年多少周"></a>计算一年多少周</h4><p>首先你得知道是不是闰年，也就是一年是365还是366.<br>其次你得知道当年1月1号是周几。假如是周五，一年365天把1号 2号3号减去，也就是把第一个不到一周的天数减去等于362<br>还得知道最后一天是周几，假如是周五，需要把周一到周五减去，也就是362-5=357.正常情况 357这个数计算出来是7的倍数。357/7=51 。即为周数。</p>
<h4 id="轮播图实现原理"><a href="#轮播图实现原理" class="headerlink" title="轮播图实现原理"></a>轮播图实现原理</h4><p>图片轮播的原理就是图片排成一行，然后准备一个只有一张图片大小的容器，对这个容器设置超出部分隐藏，在控制定时器来让这些图片整体左移或右移，这样呈现出来的效果就是图片在轮播了。<br>如果有两个轮播，可封装一个轮播组件，供两处调用。</p>
<h4 id="Java和JavaScript的区别"><a href="#Java和JavaScript的区别" class="headerlink" title="Java和JavaScript的区别"></a>Java和JavaScript的区别</h4><p><strong>从静态类型还是动态类型来看</strong><br><code>静态类型，编译的时候就能够知道每个变量的类型，编程的时候也需要给定类型</code>，如Java中的整型int，浮点型float等。C、C++、Java都属于静态类型语言。</p>
<p><code>动态类型，运行的时候才知道每个变量的类型，编程的时候无需显示指定类型</code>，如JavaScript中的var、PHP中的$。JavaScript、Ruby、Python都属于动态类型语言。</p>
<p>静态类型还是动态类型对语言的性能有很大影响。</p>
<p><code>对于静态类型</code>，在编译后会大量利用已知类型的优势，如int类型，占用4个字节，<code>编译后的代码就可以用内存地址加偏移量的方法存取变量，而地址加偏移量的算法汇编很容易实现</code>。</p>
<p><code>对于动态类型</code>，<code>会当做字符串通通存下来，之后存取就用字符串匹配</code>。</p>
<p>运行在客户端浏览器上；不用预编译，直接解析执行代码；是弱类型语言，较为灵活；与操作系统无关，跨平台的语言；脚本语言、解释性语言。</p>
<p><strong>语言的特性</strong><br>Java反射：在运行状态中，对于任意一个类，都能够知道这个类的所以属性和方法；对于任意一个对象，都能调用它的任意一个方法和属性。<br>Spring框架就是，利用反射机制实现控制反转，将java bean 放到spring容器中。</p>
<p>比如ES6中的Promise就是充分的利用了闭包的特性，将状态和值放在Promise这个闭包里面，然后通过回调来改变或者获取里面的值。</p>
<p>这样js没有反射就没办法实现一个容器，但是跟这个比较类似的有点像数组，数组也是保存了这些函数对象，等需要的时候再执行。<br>同样的java没有闭包也没办法实现一个promise，但是它处理异步有线程，或者也可以利用private或者其他什么方法让自己内部的方法不给外部调用。</p>
<h4 id="通用性能优化"><a href="#通用性能优化" class="headerlink" title="通用性能优化"></a>通用性能优化</h4><p>减少HTTP请求、使用内容发布网络（CDN）、添加本地缓存、压缩资源文件、将CSS样式表放在顶部，把javascript放在底部（浏览器的运行机制决定）、避免使用CSS表达式、减少DNS查询、使用外部javascript和CSS、避免重定向、图片lazyLoad</p>
<h4 id="实现拖拽"><a href="#实现拖拽" class="headerlink" title="实现拖拽"></a>实现拖拽</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;img draggable=<span class="string">"true"</span>&gt;</span><br></pre></td></tr></table></figure>
<h4 id="前端模块化"><a href="#前端模块化" class="headerlink" title="前端模块化"></a>前端模块化</h4><p>前端模块化就是复杂的文件编程一个一个独立的模块，比如js文件等等，分成独立的模块有利于重用（复用性）和维护（版本迭代），这样会引来模块之间相互依赖的问题，所以有了commonJS规范，AMD，CMD规范等等，以及用于js打包（编译等处理）的工具webpack</p>
<p>一个模块是能实现特定功能的文件，有了模块就可以方便的使用别人的代码，想要什么功能就能加载什么模块。<br>Commonjs：开始于服务器端的模块化，同步定义的模块化，每个模块都是一个单独的作用域，模块输出，modules.exports，模块加载require()引入模块。</p>
<p>AMD：中文名异步模块定义的意思。</p>
<p>requireJS实现了AMD规范，主要用于解决下述两个问题。</p>
<p>1.多个文件有依赖关系，被依赖的文件需要早于依赖它的文件加载到浏览器<br>2.加载的时候浏览器会停止页面渲染，加载文件越多，页面失去响应的时间越长。</p>
<p>语法：requireJS定义了一个函数define，它是全局变量，用来定义模块。</p>
<p>requireJS的例子：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//定义模块</span></span><br><span class="line">define([<span class="string">'dependency'</span>], <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">  <span class="keyword">var</span> name = <span class="string">'Byron'</span>;</span><br><span class="line">  <span class="function"><span class="keyword">function</span> <span class="title">printName</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(name);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    printName: printName</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;);</span><br><span class="line"><span class="comment">//加载模块</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">require</span>([<span class="string">'myModule'</span>], <span class="function"><span class="keyword">function</span> (<span class="params">my</span>)</span>&#123;</span><br><span class="line">  my.printName();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>requirejs定义了一个函数define,它是全局变量，用来定义模块：<br>define(id?dependencies?,factory)<br>在页面上使用模块加载函数：<br>require([dependencies],factory)；</p>
<p>总结AMD规范：require()函数在加载依赖函数的时候是<code>异步加载</code>的，这样浏览器<code>不会失去响应</code>，它指定的回调函数，<code>只有前面的模块加载成功，才会去执行</code>。<br>因为<code>网页在加载js的时候会停止渲染</code>，因此我们可以<code>通过异步的方式去加载js</code>,而如果需要依赖某些，也是异步去依赖，依赖后再执行某些方法。</p>
<h4 id="一次加载一张图片，加载完后再加载下一张"><a href="#一次加载一张图片，加载完后再加载下一张" class="headerlink" title="一次加载一张图片，加载完后再加载下一张"></a>一次加载一张图片，加载完后再加载下一张</h4><p>(1)方法1。利用image的onload事件会在图片加载完成后立即执行。onload 事件在图片加载完成后立即执行。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>&gt;</span></span><br><span class="line"><span class="javascript">  <span class="keyword">var</span> obj=<span class="keyword">new</span> Image();</span></span><br><span class="line"><span class="javascript">  obj.src=<span class="string">"http://www.phpernote.com/uploadfiles/editor/201107240502201179.jpg"</span>;</span></span><br><span class="line"><span class="javascript">  obj.onload=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">    alert(<span class="string">'图片的宽度为：'</span>+obj.width+<span class="string">'；图片的高度为：'</span>+obj.height);</span></span><br><span class="line"><span class="javascript">    <span class="built_in">document</span>.getElementById(<span class="string">"mypic"</span>).innnerHTML=<span class="string">"&lt;img src='"</span>+<span class="keyword">this</span>.src+<span class="string">"' /&gt;"</span>;</span></span><br><span class="line">  &#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"mypic"</span>&gt;</span>onloading……<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>(2)方法2。当对象的状态改变时触发。<br>IE的script 元素只支持onreadystatechange事件，不支持onload事件。<br>FF的script 元素不支持onreadystatechange事件，只支持onload事件。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>&gt;</span></span><br><span class="line"><span class="javascript">  <span class="keyword">var</span> obj=<span class="keyword">new</span> Image();</span></span><br><span class="line"><span class="javascript">  obj.src=<span class="string">"http://www.phpernote.com/uploadfiles/editor/201107240502201179.jpg"</span>;</span></span><br><span class="line"><span class="javascript">  obj.onreadystatechange=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">    <span class="keyword">if</span>(<span class="keyword">this</span>.readyState==<span class="string">"complete"</span>)&#123;</span></span><br><span class="line"><span class="javascript">      alert(<span class="string">'图片的宽度为：'</span>+obj.width+<span class="string">'；图片的高度为：'</span>+obj.height);</span></span><br><span class="line"><span class="javascript">      <span class="built_in">document</span>.getElementById(<span class="string">"mypic"</span>).innnerHTML=<span class="string">"&lt;img src='"</span>+<span class="keyword">this</span>.src+<span class="string">"' /&gt;"</span>;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"mypic"</span>&gt;</span>onloading……<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><h4 id="js字符串转数字的方法"><a href="#js字符串转数字的方法" class="headerlink" title="js字符串转数字的方法"></a>js字符串转数字的方法</h4><p>通过函数parseInt（），可解析一个字符串，并返回一个整数，语法为parseInt（string ,radix）<br>string：被解析的字符串<br>radix：表示要解析的数字的基数，默认是十进制，如果radix&lt;2或&gt;36,则返回NaN</p>
<h4 id="eval"><a href="#eval" class="headerlink" title="eval"></a>eval</h4><p>eval这个方法接受一个字符串作为参数，并将其中的内容视为好像在书写时就存在于程序中这个位置的代码。<br>它的功能是将对应的字符串解析成js并执行，应该避免使用js，因为非常消耗性能（2次，一次解析成js，一次执行）</p>
<h4 id="with"><a href="#with" class="headerlink" title="with"></a>with</h4><p>with关键字：通常被当做重复引用同一个对象的多个属性的快捷方式。<br>缺点：导致数据泄露。性能下降。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 常规赋值</span></span><br><span class="line">obj.a=<span class="number">1</span>;</span><br><span class="line">obj.b=<span class="number">2</span>;</span><br><span class="line">obj.c=<span class="number">3</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用with赋值</span></span><br><span class="line"><span class="keyword">with</span>(obj)&#123;</span><br><span class="line">  a=<span class="number">1</span>;</span><br><span class="line">  b=<span class="number">2</span>;</span><br><span class="line">  c=<span class="number">3</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="setTimeout-fn-100"><a href="#setTimeout-fn-100" class="headerlink" title="setTimeout(fn,100)"></a>setTimeout(fn,100)</h4><p>setTimeout()函数将事件插入了任务列表，100毫秒是插入宏任务队列后等待100ms。必须等到当前代码执行完，主线程才会去执行它指定的回调函数，有可能要等很久，所以没有办法保证回调函数一定会在setTimeout指定的时间内执行。</p>
<h4 id="去除字符串首尾空格"><a href="#去除字符串首尾空格" class="headerlink" title="去除字符串首尾空格"></a>去除字符串首尾空格</h4><p>使用正则<code>(^\s*)|(\s*$)</code>即可。意识是：以空格开头或者以空格结尾，\s表示空格。</p>
<h4 id="indexOf和startWith的区别"><a href="#indexOf和startWith的区别" class="headerlink" title="indexOf和startWith的区别"></a>indexOf和startWith的区别</h4><p>indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。如果没有找到匹配的字符串则返回 -1。区分大小写。<br>startsWith() 方法用于检测字符串是否以指定的子字符串开始。如果是以指定的子字符串开头返回 true，否则 false。区分大小写。</p>
<h4 id="图片的懒加载和预加载"><a href="#图片的懒加载和预加载" class="headerlink" title="图片的懒加载和预加载"></a>图片的懒加载和预加载</h4><p>预加载：提前加载图片，当用户需要查看时可直接从本地缓存中渲染。<br>懒加载：懒加载的主要目的是作为服务器前端的优化，减少请求数或延迟请求数。<br>两种技术的本质：两者的行为是相反的，一个是提前加载，一个是迟缓甚至不加载。<br>懒加载对服务器前端有一定的缓解压力作用，预加载则会增加服务器前端压力。</p>
<h4 id="参数获取"><a href="#参数获取" class="headerlink" title="参数获取"></a>参数获取</h4><p>…rest获取参数<br>arguments是类数组对象，有length属性，不能调用数组方法。可用Array.from()转换。</p>
<h4 id="暂停死区"><a href="#暂停死区" class="headerlink" title="暂停死区"></a>暂停死区</h4><p>在代码块内，使用let、const命令声明变量之前，该变量都是不可用的。因为他们时没办法变量提升的。这在语法上，称为“暂时性死区”。</p>
<h4 id="js垃圾回收机制"><a href="#js垃圾回收机制" class="headerlink" title="js垃圾回收机制"></a>js垃圾回收机制</h4><p>什么是垃圾<br>一般来说没有被引用的对象就是垃圾，就是要被清除， 有个例外如果几个对象引用形成一个环，互相引用，但根访问不到它们，这几个对象也是垃圾，也要被清除。</p>
<h4 id="var-let-const的区别"><a href="#var-let-const的区别" class="headerlink" title="var let const的区别"></a>var let const的区别</h4><p>var声明的变量是全局或者整个函数块的，而let,const声明的变量是块级的变量。<br>var声明的变量存在变量提升，let,const不存在。<br>let声明的变量允许重新赋值，const不允许。</p>
<h4 id="获得对象上的属性"><a href="#获得对象上的属性" class="headerlink" title="获得对象上的属性"></a>获得对象上的属性</h4><p>从ES5开始，有三种方法可以列出对象的属性</p>
<ul>
<li><code>for(let i in obj)</code>：该方法依次访问一个对象及其原型链中<code>所有可枚举</code>的类型。</li>
<li><code>Object.keys(obj)</code>：返回一个数组，包括<code>所有可枚举</code>的属性名称。</li>
<li><code>Object.getOwnPropertyNames(obj)</code>：返回一个数组<code>包含不可枚举</code>的属性。</li>
</ul>
<h4 id="利用js保留关键字arguments获取函数参数"><a href="#利用js保留关键字arguments获取函数参数" class="headerlink" title="利用js保留关键字arguments获取函数参数"></a>利用js保留关键字arguments获取函数参数</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> fn = [].shift.call(<span class="built_in">arguments</span>)</span><br><span class="line"><span class="comment">//返回第一个参数</span></span><br><span class="line"><span class="comment">//改变原数组，现在的arguments第一个参数被干掉了。</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> args = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>, <span class="number">1</span>);</span><br><span class="line"><span class="comment">//</span></span><br><span class="line"><span class="comment">//不会改变原始数组</span></span><br></pre></td></tr></table></figure>
<h4 id="js中的各种位置"><a href="#js中的各种位置" class="headerlink" title="js中的各种位置"></a>js中的各种位置</h4><p>clientHeight：表示的是可视区域的高度，不包含border和滚动条<br><img src="client-height.png"></p>
<p>offsetHeight：表示可视区域的高度，包含了border和滚动条<br><img src="offset-height.png"></p>
<p>scrollHeight：表示了所有区域的高度，包含了因为滚动被隐藏的部分。<br><img src="scroll-height.png"></p>
<p>clientTop：表示边框border的厚度，在未指定的情况下一般为0。<br>scrollTop：滚动后被隐藏的高度，获取对象相对于由offsetParent属性指定的父坐标(css定位的元素或body元素)距离顶端的高度。</p>
<h4 id="变量提升"><a href="#变量提升" class="headerlink" title="变量提升"></a>变量提升</h4><p>在编译的过程中，先将<code>标识符</code>和<code>函数声明</code>给提升到其对应的作用域的<code>顶端</code>。标识符解析的时候，会进行LHS查询，在LHS查询的时候，如果标识符一直找不到声明的位置，那么最终就会在全局环境生成一个全局变量。 LHS ： 指的是赋值操作的左端。<br>说到LHS查询，就不得不提对应的RHS查询，相信大家已经看出RHS的意思了把，它指的是赋值操作的源头。RHS查询的时候，如果找不到对应的标识符，就会抛出一个异常：ReferenceError。</p>
<p>函数提升和变量提升还有点不一样。函数提升，<code>只会提升函数声明</code>，而<code>不会提升函数表达式</code>。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">console</span>.log(<span class="keyword">typeof</span> a);</span><br><span class="line">a();</span><br><span class="line"><span class="keyword">var</span> a = <span class="number">3</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">a</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"> <span class="built_in">console</span>.log(<span class="keyword">typeof</span> a);</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">typeof</span> a);</span><br><span class="line">a = <span class="number">6</span>;</span><br><span class="line">a();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 变量提升后会变成这个</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">a</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="keyword">typeof</span> a);</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">typeof</span> a);</span><br><span class="line">a();</span><br><span class="line">a = <span class="number">3</span>;</span><br><span class="line"><span class="built_in">console</span>.log(<span class="keyword">typeof</span> a);</span><br><span class="line">a = <span class="number">6</span>;</span><br><span class="line">a();</span><br></pre></td></tr></table></figure>
<h2 id="计算机网络"><a href="#计算机网络" class="headerlink" title="计算机网络"></a>计算机网络</h2><h3 id="CDN原理"><a href="#CDN原理" class="headerlink" title="CDN原理"></a>CDN原理</h3><p>CDN的全称是Content Delivery Network，即内容分发网络。CDN的基本原理是广泛采用各种缓存服务器，将这些缓存服务器分布到用户访问相对集中的地区或网络中，在用户访问网站时，利用全局负载技术将用户的访问指向距离最近的工作正常的缓存服务器上，由缓存服务器直接响应。</p>
<h3 id="输入url"><a href="#输入url" class="headerlink" title="输入url"></a>输入url</h3><p>DNS解析，把域名解析成对应的ip<br>TCP连接，连接到ip<br>发送HTTP请求，向ip发送请求<br>服务器处理请求并返回HTTP报文<br>浏览器解析渲染页面<br>连接结束</p>
<h3 id="head请求option"><a href="#head请求option" class="headerlink" title="head请求option"></a>head请求option</h3><p>Head只请求页面的首部，head方法和get方法相同，只不过服务器响应时不会返回消息体，一个head请求的响应中，http头中包含的元信息应该和一个get请求的响应消息相同，这种方法可以用来获取请求中隐含的元信息，而不用传输实体本身，这个也经常用来测试超链接的有效性和可用性，</p>
<p>Head请求有以下特点：<br>只请求资源的首部，<br>检查超链接的有效性<br>检查网页是否被修改<br>用于自动搜索机器人获取网页的标志信息，获取rss种子信息，或者传递安全认证信息等</p>
<h3 id="OSI七层模型"><a href="#OSI七层模型" class="headerlink" title="OSI七层模型"></a>OSI七层模型</h3><p>应用层：文件传输，常用协议HTTP，snmp,FTP ,<br>表示层：数据格式化，代码转换，数据加密，<br>会话层：建立，解除会话<br><code>传输层</code>：提供端对端的接口，tcp,udp<br><code>网络层</code>：为数据包选择路由，IP，icmp<br>数据链路层：传输有地址的帧 802.11<br>物理层：二进制的数据形式在物理媒体上传输数据</p>
<h3 id="TCP-IP的网络模型"><a href="#TCP-IP的网络模型" class="headerlink" title="TCP/IP的网络模型"></a>TCP/IP的网络模型</h3><p>TCP/IP模型是一系列网络协议的总称，这些协议的目的是使得计算机之间可以进行信息交换，<br>TCP/IP模型四层架构从下到上分别是链路层，<code>网络层</code>，<code>传输层</code>，应用层</p>
<p>应用层负责传送各种最终形态的数据，是直接与用户信息打交道的层，主要协议是http，ftp等<br>传输层负责传送文本数据，主要协议是TCP<br>网络层负责分配地址和传送二进制数据，主要协议是IP协议，<br>链路层的作用是负责建立电路连接，是整个网络的物理基础，典型的协议包括以太网，ADSL等，</p>
<h3 id="HTTP状态码"><a href="#HTTP状态码" class="headerlink" title="HTTP状态码"></a>HTTP状态码</h3><p>状态码可以按照第一个数字分类，1表示信息，2表示成功，3表示重定向，4表示客户端错误，5表示服务器错误。<br>常见的状态码有101切换协议，200成功，301永久重定向，302临时重定向，304未修改。<br>301和302的区别：301：永久移动，请求的网页已永久移动到新的位置，服务器返回此响应，会自动将请求者转到新位置，302：历史移动，服务器目前从不同位置的网页响应请求，但请求者应继续使用原有位置来继续以后的请求。<br>200和304：200表示成功，服务器已成功处理了请求，通常表示为服务器提供了请求的网页，304表示未修改，自从上次请求后，请求的网页未修改过，服务器返回此响应时不会返回网页内容。</p>
<p>n200 OK，当GET请求成功完成，DELETE或者PATCH请求同步完成。<br>n201 Created，对于那些要服务器创建对象的请求来说，资源已创建完毕。<br>n202 Accepted，POST，DELETE或者PATCH请求提交成功，稍后将异步的进行处理。<br>n204 No Content，Response中包含一些Header和一个状态行， 但不包括实体的主题内容（没有response body）<br>n304 Not Modified，客户的缓存资源是最新的， 要客户端使用缓存<br>n400 Bad Request<br>  require_argument 缺少参数<br>  invalid_argument 无效参数<br>n401 Unauthorized: 请求失败，因为用户没有进行认证<br>  auth_token_expired 授权已过期<br>  auth_invalid_token 无效的授权(如token不存在、需要mac签名、mac签名无效、nonce无效、重复提交等)<br>n403 Forbidden: 请求失败，因为用户被认定没有访问特定资源的权限<br>  auth_denied 授权受限（无权限或IP地址受限等）<br>n405 Method Not Allowed：不支持该 Request 的方法<br>n406 Not Acceptable：请求的资源的内容特性无法满足请求头中的条件，因而无法生成响应实体。<br>n415 Unsupported Media Type: 对于当前请求的方法和所请求的资源，请求中提交的实体并不是服务器中所支持的格式，因此请求被拒绝。<br>n429 Too Many Requests: 请求频率超配，稍后再试。<br>n500 Internal Server Error: 服务器遇到一个错误，使其无法为请求提供服务<br>n501 Not Implemented：客户端发起的请求超出服务器的能力范围(比如，使用了服务器不支持的请求方法)时，使用此状态码。<br>n502 Bad Gateway：代理使用的服务器遇到了上游的无效响应<br>n503 Service Unavailable：服务器目前无法为请求提供服务，但过一段时间就可以恢复服务</p>
<h3 id="跨域"><a href="#跨域" class="headerlink" title="跨域"></a>跨域</h3><p>浏览器的安全机制要求必须同源策略才可以访问，同源指的是：协议、域名、端口要都一样。跨域指的是在不同源的情况下进行的访问。</p>
<p>(new Image()).src=’xxxx’。可以允许跨域。<br>allow-origin</p>
<h4 id="JSONP"><a href="#JSONP" class="headerlink" title="JSONP"></a>JSONP</h4><p>全称为json with padding，解决老版本浏览器跨域数据访问问题，原理是web页面调用JS文件不受浏览器同源策略限制，所以通过script标签可以进行跨域请求，流程如下：</p>
<ul>
<li>首先前端设置好<code>回调函数名称</code>，并将其作为URL的参数。</li>
<li>服务器端收到请求后，通过该参数<code>获取到回调函数名</code>，并<code>将数据放在参数中返回</code>。</li>
<li>收到结果后因为是script标签，所以<code>浏览器当做脚本运行</code>，</li>
</ul>
<h4 id="cors"><a href="#cors" class="headerlink" title="cors"></a>cors</h4><p>全称是跨域资源共享，允许浏览器向跨源服务器发出XMLHTTP Request请求，从而克服了ajax只能同源使用的策略，实现cors的关键是服务器，只要服务器实现了cros接口，就可以跨域通信。</p>
<p>服务端设置Access-Control-Allow-Origin即可，前端无须设置，若要带cookie请求，前后端都需要设置。</p>
<p>前端逻辑很简单，正常发起ajax请求即可，成功的关键在于服务器 Access-Control-Allow-Origin 是否包含请求页面的域名，如果不包含的话，浏览器将认为这是一次失败的异步请求，将会调用 xhr.onerror 中的函数。<br>Cros使用简单，支持POST方式，但是存在兼容问题<br>浏览器将cors请求分为两类，简单请求和非简单请求，对于简单请求，浏览器直接发出cors请求，就是在头信息之中增加一个origin字段，用于说明本次请求来自哪个协议+域名+端口，服务器根据这个值，决定是否同意本次请求，如果服务器同意本次请求，返回的响应中会多出几个头信息字段：</p>
<p>Access-Control-Allow-Orign：返回origin的字段或者*<br>Access-Control-Allow-Credentials,该字段可选，是一个bool值，表示是否允许发送cookie，<br>Access-Control-Expose-Headers</p>
<h4 id="服务器代理"><a href="#服务器代理" class="headerlink" title="服务器代理"></a>服务器代理</h4><p>即当你有跨域的请求操作时发给后端，让后端帮你代为请求。启一个代理服务器，实现数据的转发。</p>
<h4 id="location-hash-iframe跨域"><a href="#location-hash-iframe跨域" class="headerlink" title="location.hash + iframe跨域"></a>location.hash + iframe跨域</h4><p>a欲与b跨域相互通信，通过中间页c来实现。 三个页面，不同域之间利用iframe的location.hash传值，相同域之间直接js访问来通信。</p>
<h4 id="window-name-iframe跨域"><a href="#window-name-iframe跨域" class="headerlink" title="window.name + iframe跨域"></a>window.name + iframe跨域</h4><p>通过iframe的src属性由外域转向本地域，跨域数据即由iframe的window.name从外域传递到本地域。</p>
<h4 id="postMessage跨域"><a href="#postMessage跨域" class="headerlink" title="postMessage跨域"></a>postMessage跨域</h4><p>可以跨域操作的window属性之一。window.psotMessage()</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//发送方</span></span><br><span class="line">otherWindow.postMessage(message, targetOrigin, [transfer]);</span><br><span class="line">receiver.postMessage(<span class="string">"Hello ！"</span>, <span class="string">"https://c.runoob.com"</span>);</span><br><span class="line"><span class="comment">//接收方</span></span><br><span class="line"><span class="built_in">window</span>.addEventListener(<span class="string">'message'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">e</span>) </span>&#123;  <span class="comment">// 监听 message 事件</span></span><br><span class="line">  <span class="built_in">console</span>.log(e.data)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="token"><a href="#token" class="headerlink" title="token"></a>token</h4><p>api_token = md5 (‘模块名’ + ‘控制器名’ + ‘方法名’ + ‘2017-07-18’ + ‘加密密钥’) = 770fed4ca2aabd20ae9a5dd774711de2<br>user_token 存储用户信息、时间戳等信息，服务端接收到请求后验证通过了，则更新token</p>
<h3 id="HTTP缓存机制"><a href="#HTTP缓存机制" class="headerlink" title="HTTP缓存机制"></a>HTTP缓存机制</h3><p>浏览器缓存(Brower Caching)是浏览器对之前请求过的文件进行缓存，以便下一次访问时重复使用，节省带宽，提高访问速度，降低服务器压力</p>
<h4 id="强缓存和协商缓存"><a href="#强缓存和协商缓存" class="headerlink" title="强缓存和协商缓存"></a>强缓存和协商缓存</h4><p>强缓存：浏览器不会像服务器发送任何请求，直接从本地缓存中读取文件并返回Status Code: 200 OK<br>200 form memory cache : 不访问服务器，一般已经加载过该资源且缓存在了内存当中，直接<code>从内存中读取缓存</code>。浏览器关闭后，数据将不存在（资源被释放掉了），再次打开相同的页面时，不会出现from memory cache。<br>200 from disk cache： 不访问服务器，已经在之前的某个时间加载过该资源，直接<code>从硬盘中读取缓存</code>，关闭浏览器后，数据依然存在，此资源不会随着该页面的关闭而释放掉下次打开仍然会是from disk cache。<br><code>优先</code>访问<code>memory</code> cache,<code>其次</code>是<code>disk</code> cache，<code>最后</code>是请求<code>网络</code>资源。</p>
<p>协商缓存: 向服务器发送请求，服务器会根据这个请求的参数来判断是否命中协商缓存，如果命中，则返回304状态码并带上新的response header通知浏览器从缓存中读取资源；</p>
<h4 id="强缓存"><a href="#强缓存" class="headerlink" title="强缓存"></a>强缓存</h4><p>cache-control是http1.1的头字段，expires是http1.0的头字段,如果expires和cache-control同时存在，cache-control会覆盖expires，建议两个都写。<br>Expires：过期时间，如果设置了时间，则浏览器会在设置的时间内直接读取缓存，不再请求<br>cache-control：<br>（1）max-age：用来设置资源（representations）可以被<code>缓存多长时间</code>，单位为秒；<br>（2）s-maxage：和max-age是一样的，不过它只针<code>对代理服务器缓存</code>而言；<br>（3）public：指示响应可被任何缓存区缓存；<br>（4）private：只能针对个人用户，而不能被代理服务器缓存；<br>（5）no-cache：<code>每次发起请求都会评估缓存响应的有效性</code>。强制客户端直接向服务器发送请求,也就是说每次请求都必须向服务器发送。服务器接收到请求，然后判断资源是否变更，是则返回新内容，否则返回304，未变更；这个很容易让人产生误解，使人误     以为是响应不被缓存。实际上Cache-Control:no-cache是会被缓存的，只不过每次在向客户端（浏览器）提供响应数据时，缓存都要向服务器评估缓存响应的有效性；<br>（6）no-store：<code>禁止一切缓存</code>（这个才是响应不被缓存的意思）；</p>
<h4 id="协商缓存"><a href="#协商缓存" class="headerlink" title="协商缓存"></a>协商缓存</h4><p>Last-Modifed/If-Modified-Since和Etag/If-None-Match是分别成对出现的，呈一一对应关系<br>Etag/If-None-Match：<br>Etag是属于HTTP 1.1属性，它是由服务器（Apache或者其他工具）生成返回给前端，用来帮助服务器控制Web端的缓存验证。<br>Apache中，ETag的值，默认是对文件的索引节（INode），大小（Size）和最后修改时间（MTime）进行Hash后得到的。</p>
<p>当资源过期时，浏览器发现响应头里有Etag,则再次像服务器请求时带上请求头if-none-match(值是Etag的值)。服务器收到请求进行比对，决定返回200或304。如果不一样则获取新的，如果一样则读取缓存。</p>
<p>Last-Modifed/If-Modified-Since：<br>若最后修改时间较新（Last-Modified &gt; If-Modified-Since），说明资源有被改过，则返回最新资源，HTTP 200 OK;<br>若最后修改时间较旧（Last-Modified &lt; If-Modified-Since），说明资源无新修改，响应HTTP 304 走缓存。</p>
<p>Last-Modifed/If-Modified-Since的时间精度是秒，而Etag可以更精确。<br>Etag优先级是高于Last-Modifed的，所以服务器会优先验证Etag<br>Last-Modifed/If-Modified-Since是http1.0的头字段</p>
<h3 id="TCP三次握手"><a href="#TCP三次握手" class="headerlink" title="TCP三次握手"></a>TCP三次握手</h3><h4 id="报文内容介绍"><a href="#报文内容介绍" class="headerlink" title="报文内容介绍"></a>报文内容介绍</h4><p>16位端口号：源端口号，主机该报文段是来自哪里；目标端口号，要传给哪个上层协议或应用程序。不需要记录IP地址，因为IP地址是在网络层处理的。这里是传输层主要解决传输问题。<br>32位序列号：一次TCP通信（从TCP连接建立到断开）过程中某一个传输方向上的字节流的每个字节的编号。<br>32位确认号：用作对另一方发送的tcp报文段的响应。其值是收到的TCP报文段的序号值加1。<br>4位头部长度：4位最大能标识15，所以TCP头部最长是60字节。<br>6位标志位：URG(紧急指针是否有效)，ACk（表示确认号是否有效），PSH（缓冲区尚未填满），RST（表示要求对方重新建立连接），SYN（建立连接消息标志接），FIN（表示告知对方本端要关闭连接了）<br>16位窗口大小：是TCP流量控制的一个手段。这里说的窗口，指的是接收通告窗口。它告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据，这样对方就可以控制发送数据的速度。<br>16位校验和：由发送端填充，接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。注意，这个校验<code>不仅包括TCP头部，也包括数据部分</code>。这也是TCP可靠传输的一个重要保障。<br>16位紧急指针：一个正的偏移量。它和序号字段的值相加表示最后一个紧急数据的下一字节的序号。因此，确切地说，这个字段是紧急指针相对当前序号的偏移，不妨称之为紧急偏移。TCP的紧急指针是发送端向接收端发送紧急数据的方法。</p>
<p><img src="tcp-packet.jpg"><br><img src="tcp-packet2.jpg"></p>
<p><img src="tcp-flow.jpg"></p>
<p>要理解整个TCP三次握手的过程可以从几个方面拆开理解，然后再结合起来。</p>
<h4 id="序列号和确认号"><a href="#序列号和确认号" class="headerlink" title="序列号和确认号"></a>序列号和确认号</h4><p>第一次握手：客户端发送<code>序列号</code>，服务端接收到后<code>把客户端的序列号+1作为确认号</code>，服务端发送<code>确认号</code>和<code>序列号</code><br>第二次握手：客户端接收到后<code>验证客户端的序列号+1是否和服务端的确认号相等</code>并且<code>把服务端的序列号+1作为确认号</code>，客户端发送<code>确认号</code>和<code>序列号</code><br>第三次握手：服务端接收到后<code>验证服务端的序列号+1是否和客户端的确认号相等</code></p>
<h4 id="SYN和ACK标志位"><a href="#SYN和ACK标志位" class="headerlink" title="SYN和ACK标志位"></a>SYN和ACK标志位</h4><p>第一次握手：客户端发送的报文SYN=1<br>第二次握手：服务端发送的报文SYN=1，ACK=1<br>第三次握手，客户端发送的报文ACK=1</p>
<p>其实可以理解成<br>第一次握手：客户端发送的报文SYN=1<br>第二次握手：服务端发送的报文ACK=1<br>第三次握手：服务端发送的报文SYN=1<br>第四次握手，客户端发送的报文ACK=1</p>
<p>但是其实第二次和第三次可以合起来，因为它都是从服务端发往客户端，<br>这样子客户端SYN=1,ACK=1，服务端SYN=1,ACK=1，就建立了可靠连接。</p>
<h4 id="状态"><a href="#状态" class="headerlink" title="状态"></a>状态</h4><p>开始之前客户端和服务端都是关闭状态closed<br>第一次握手：客户端变成发送状态syn-send，服务端变成接收状态syn-rcvd<br>第二次握手：客户端变成连接状态established<br>第三次握手：服务端变成连接状态established<br>可以开始通讯。</p>
<h4 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h4><h5 id="TCP和UDP的区别"><a href="#TCP和UDP的区别" class="headerlink" title="TCP和UDP的区别"></a>TCP和UDP的区别</h5><p>TCP是一个面向连接的、可靠的、基于字节流的传输层协议。而UDP是一个面向无连接的传输层协议。<br>具体来分析，和 UDP 相比，TCP 有三大核心特性:</p>
<ul>
<li>面向连接。所谓的连接，指的是客户端和服务器的连接，在双方互相通信之前，TCP 需要三次握手建立连接，而 UDP 没有相应建立连接的过程。</li>
<li>可靠性。TCP 花了非常多的功夫保证连接的可靠，这个可靠性体现在哪些方面呢？一个是有状态，另一个是可控制。<br>TCP 会精准记录哪些数据发送了，哪些数据被对方接收了，哪些没有被接收到，而且保证数据包按序到达，不允许半点差错。这是有状态。<br>当意识到丢包了或者网络环境不佳，TCP 会根据具体情况调整自己的行为，控制自己的发送速度或者重发。这是可控制。<br>相应的，UDP 就是无状态, 不可控的。</li>
<li>面向字节流。UDP 的数据传输是基于数据报的，这是因为仅仅只是继承了 IP 层的特性，而 TCP 为了维护状态，将一个个 IP 包变成了字节流。</li>
</ul>
<h5 id="TCP为什么是三次而不是两次、四次"><a href="#TCP为什么是三次而不是两次、四次" class="headerlink" title="TCP为什么是三次而不是两次、四次?"></a>TCP为什么是三次而不是两次、四次?</h5><h5 id="TCP如何保证可靠性"><a href="#TCP如何保证可靠性" class="headerlink" title="TCP如何保证可靠性"></a>TCP如何保证可靠性</h5><p>首先，TCP的连接是基于三次握手，而断开则是四次挥手。确保连接和断开的可靠性。<br>其次，TCP的可靠性，还体现在有状态;TCP会记录哪些数据发送了，哪些数据被接受了，哪些没有被接受，并且保证数据包按序到达，保证数据传输不出差错。<br>再次，TCP的可靠性，还体现在可控制。它有数据包校验、ACK应答、超时重传(发送方)、失序数据重传（接收方）、丢弃重复数据、流量控制（滑动窗口）和拥塞控制等机制。</p>
<h5 id="POST和GET的区别"><a href="#POST和GET的区别" class="headerlink" title="POST和GET的区别"></a>POST和GET的区别</h5><p>请求参数：GET 把参数包含在 URL 中，用&amp;连接起来；POST 通过 request body 传递参数。<br>请求缓存：GET请求会被主动Cache，而POST请求不会，除非手动设置。<br>收藏为书签：GET请求支持收藏为书签，POST请求不支持。<br>安全性：POST比GET安全，GET请求在浏览器回退时是无害的，而POST会再次请求。<br>历史记录：GET请求参数会被完整保留在浏览历史记录里，而POST中的参数不会被保留。<br>编码方式：GET请求只能进行url编码，而POST支持多种编码方式。<br>参数数据类型：GET只接受ASCII字符，而POST没有限制数据类型。<br>数据包: GET产生一个TCP数据包；POST可能产生两个TCP数据包。<br>缓存：get请求类似于查找的过程，用户获取数据，可以不用每次都与数据库连接，所以可以使用缓存。post不同，post做的一般是修改和删除的工作，所以必须与数据库交互，所以不能使用缓存。因此get请求适合于请求缓存。<br>参数长度：HTTP 协议 未规定 GET 和POST的长度限制。GET的最大长度显示是因为 浏览器和 web服务器限制了 URI的长度。不同的浏览器和WEB服务器，限制的最大长度不一样。要支持IE，则最大长度为2083byte，若只支持Chrome，则最大长度 8182byte</p>
<h3 id="HTTP协议"><a href="#HTTP协议" class="headerlink" title="HTTP协议"></a>HTTP协议</h3><h4 id="HTTPS"><a href="#HTTPS" class="headerlink" title="HTTPS"></a>HTTPS</h4><p>使用数字证书的流程</p>
<ol>
<li>用户在浏览器发起HTTPS请求（如 juejin.cn），默认使用服务端的443端口进行连接；</li>
<li>HTTPS需要使用一套CA数字证书，证书内会附带一个公钥Pub，而与之对应的私钥Private保留在服务端不公开；</li>
<li>服务端收到请求，<code>返回</code>配置好的<code>包含公钥Pub的证书</code>给客户端；</li>
<li>客户端收到证书，校验合法性，主要包括是否在有效期内、证书的域名与请求的域名是否匹配，上一级证书是否有效（递归判断，直到判断到系统内置或浏览器配置好的根证书），如果不通过，则显示HTTPS警告信息，如果通过则继续；</li>
<li>客户端生成一个用于<code>对称加密的随机Key</code>，并用证书内的<code>公钥Pub进行加密</code>，发送给服务端；</li>
<li>服务端收到随机Key的密文，使用与公钥Pub配对的<code>私钥Private进行解密</code>，<code>得到</code>客户端真正想发送的<code>随机Key</code>；</li>
<li>服务端使用客户端发送过来的<code>随机Key</code>对要传输的HTTP数据进行<code>对称加密</code>，将密文返回客户端；</li>
<li>客户端使用<code>随机Key对称解密</code>密文，得到HTTP数据明文；</li>
<li>后续HTTPS请求使用之前交换好的随机Key进行对称加解密。</li>
</ol>
<p>没有使用数字证书的流程，拦截有可能发生在第三和</p>
<ol start="3">
<li>服务端收到请求，返回配置好的公钥Pub给客户端；<br>拦截：第三方进行拦截，在自己这边用自己的私钥生成一个公钥，然后传递给客户端。</li>
<li>没有。由于没有使用证书，所以这里第四步没有校验证书的环节；</li>
<li>客户端，收到公钥，用公钥加密数据，把加密后的数据发给服务端。<br>拦截：第三方进行拦截，用自己的私钥解密客户端发送的数据，获得原文后用真正服务端的公钥进行加密，然后返回给服务端。</li>
<li>服务端，收到加密的数据，用私钥解密，获得原文内容。</li>
</ol>
<h4 id="HTTP2-0"><a href="#HTTP2-0" class="headerlink" title="HTTP2.0"></a>HTTP2.0</h4><p>HTTP1.0/HTTP1.1<br>HTTP协议的主要特点。简单：快速uri唯一；灵活：可以完成不同数据类型的传输；无连接：连接一次就断掉，不会保持链接；无状态：服务端不保存客户端请求的状态。<br>HTTP报文的组成部分。请求报文：请求行（http方法，页面地址，协议，版本1.1），请求头（key value值），空行（分隔请求头和请求体），请求体；响应报文：状态行，响应头，空行，响应体。<br>HTTP方法。GET获取资源，POST传输资源，PUT更新资源，DELETE删除资源，HEAD获得报文首部，OPTION预请求一次能成功才接着往下。<br>POST和GET的区别。GET回退无害，POST会再次请求。GET请求会被浏览器主动缓存POST不行。GET请求参数会被完整的保留在浏览器历史里面POST不会，预防CSRF可以把GET改成POST。GET长度有限制2kb不同浏览器不一样。GET比较不安全参数直接放在url里面，POST放在body里面。<br>HTTP状态码。1xx指示信息，2xx成功，3xxurl已被重定向、缓存，4xx客户端错误参数错误、授权过期、不允许访问、不支持方法，5xx服务端错误内部错误、无效响应。<br>什么是持久连接。1.1支持1.0不支持keep-alive模式，持续有效，避免重新建立连接。<br>什么是管线化。在持久连接的前提request1，request2，request3一并发送，然后服务端返回response1，response2，response3</p>
<p>HTTP2.0<br>特点是：在不改动HTTP语义、方法、状态码、URI及首部字段的情况下，大幅度提高了web性能。<br>二进制传输：在应用层（HTTP2.0）和传输层（TCP or UDP）之间增加一个二进制分帧层。首部信息会被封装到Headers帧，而Request Body则封装到Data帧<br>多路复用：在一个TCP连接中存在多个流，即可以同时发送多个请求。在客户端，这些帧乱序发送，到对端后再根据每个帧首部的流标识符重新组装。通过该技术，可以避免HTTP旧版本的队头阻塞问题，极大提高传输性能。我们原来针对这种场景做的优化是用雪碧图，这样图片只要加载一次，但是用多路复用则是根本上解决问题，直接一次发送多个请求，返回一次返回多个请求。<br>Header压缩：HTTP1的Header信息没有压缩每次都需要几百~几千字节。HTTP2用HPACK压缩算法，减小header的大小，记录header并维护索引表，下次再传输只要找到对应的索引就可以，不用重复传递太多的额外信息。<br>服务端push。<br>更安全。使用了tls的拓展ALPN做为协议升级，禁用不安全的算法。</p>
<h3 id="安全"><a href="#安全" class="headerlink" title="安全"></a>安全</h3><h4 id="XSS和CSRF"><a href="#XSS和CSRF" class="headerlink" title="XSS和CSRF"></a>XSS和CSRF</h4><p>XSS基本概念。跨站脚本攻击。跨站脚本攻击Cross Site Scripting<br>XSS原理。不需要登录认证，在提交区注入脚本，在合法的页面注入js。通过合法的途径输入不合法的内容。<br>XSS防范措施。过滤特殊字段，转义特殊字符。转义输入内容，过滤敏感字符</p>
<p>CSRF基本概念。跨站请求伪造。跨站请求伪造Cross-site request forgery<br>CSRF原理。登录A网站保存了cookie，访问B网站引诱用户点击发起了请求A网站的接口。用户登录过后拿到用户的cookie然后伪造用户的请求。<br>CSRF防范措施。token验证（服务器下发的token，自动请求的接口不会带token，而且token一般没办法伪造）、referer验证（验证来源是不是A网站）、隐藏令牌（放在head头中）增加token验证。</p>
<h4 id="理解CSRF，记住几句话"><a href="#理解CSRF，记住几句话" class="headerlink" title="理解CSRF，记住几句话"></a>理解CSRF，记住几句话</h4><p>现在的应用很多都是前后端分离，后端设置“Access-Control-Allow-Origin=*”允许跨域访问，才有了CSRF这个问题。<br>cookie的共享机制，浏览器打开多个网站会有多个tab，在网站B点击了某个操作，可以发起网站A的请求并且会自动把cookie带过去。这样就造成了再网站B合法访问网站A的额情况。<br>设置cookie的httponly=true，js则无法读取和修改cookies</p>
<h4 id="XSS-漏洞的发生和修复"><a href="#XSS-漏洞的发生和修复" class="headerlink" title="XSS 漏洞的发生和修复"></a>XSS 漏洞的发生和修复</h4><p>通常页面中包含的用户输入内容都在固定的容器或者属性内，以文本的形式展示。<br>攻击者利用这些页面的用户输入片段，拼接特殊格式的字符串，突破原有位置的限制，形成了代码片段。<br>攻击者通过在目标网站上注入脚本，使之在用户的浏览器上运行，从而引发潜在风险。<br>通过 HTML 转义，可以防止 XSS 攻击。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">value</span>=<span class="string">"&lt;%= getParameter("</span><span class="attr">keyword</span>") %&gt;</span>"&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>搜索<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">  您搜索的关键词是：<span class="tag">&lt;<span class="name">%=</span> <span class="attr">getParameter</span>("<span class="attr">keyword</span>") %&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>当浏览器请求 <code>http://xxx/search?keyword=&quot;&gt;&lt;script&gt;alert(&#39;XSS&#39;);&lt;/script&gt;</code>时，服务端会解析出请求参数 keyword，得到 <code>&quot;&gt;&lt;script&gt;alert(&#39;XSS&#39;);&lt;/script&gt;</code>，拼接到 HTML 中返回给浏览器。形成了如下的 HTML：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">value</span>=<span class="string">""</span>&gt;</span><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript">alert(<span class="string">'XSS'</span>);</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span>"&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>搜索<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">  您搜索的关键词是："&gt;<span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript">alert(<span class="string">'XSS'</span>);</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>浏览器无法分辨出 <code>&lt;script&gt;alert(&#39;XSS&#39;);&lt;/script&gt;</code> 是恶意代码，因而将其执行。这里不仅仅 div 的内容被注入了，而且 input 的 value 属性也被注入， alert 会弹出两次。</p>
<p>解决办法</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">value</span>=<span class="string">"&lt;%= escapeHTML(getParameter("</span><span class="attr">keyword</span>")) %&gt;</span>"&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>搜索<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">  您搜索的关键词是：<span class="tag">&lt;<span class="name">%=</span> <span class="attr">escapeHTML</span>(<span class="attr">getParameter</span>("<span class="attr">keyword</span>")) %&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>escapeHTML() 按照如下规则进行转义：|字符|转义后的字符| |-|-| |&amp;|&amp;| |&lt;|&lt;| |&gt;|&gt;| |”|&quot;| |’|&#x27;| |/|&#x2F;|经过了转义函数的处理后，最终浏览器接收到的响应为</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"text"</span> <span class="attr">value</span>=<span class="string">"<span class="symbol">&amp;quot;</span><span class="symbol">&amp;gt;</span><span class="symbol">&amp;lt;</span>script<span class="symbol">&amp;gt;</span>alert(<span class="symbol">&amp;#x27;</span>XSS<span class="symbol">&amp;#x27;</span>);<span class="symbol">&amp;lt;</span><span class="symbol">&amp;#x2F;</span>script<span class="symbol">&amp;gt;</span>"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>搜索<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">  您搜索的关键词是：<span class="symbol">&amp;quot;</span><span class="symbol">&amp;gt;</span><span class="symbol">&amp;lt;</span>script<span class="symbol">&amp;gt;</span>alert(<span class="symbol">&amp;#x27;</span>XSS<span class="symbol">&amp;#x27;</span>);<span class="symbol">&amp;lt;</span><span class="symbol">&amp;#x2F;</span>script<span class="symbol">&amp;gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>恶意代码都被转义，不再被浏览器执行，而且搜索词能够完美的在页面显示出来。</p>
<p>注意特殊的 HTML 属性、JavaScript API<br>做了 HTML 转义，并不等于高枕无忧。<br>对于链接跳转，如 &lt;a href=”xxx” 或 location.href=”xxx”，要检验其内容，禁止以 javascript: 开头的链接，和其他非法的 scheme。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"&lt;%= escapeHTML(getParameter("</span><span class="attr">redirect_to</span>")) %&gt;</span>"&gt;跳转...<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>这段代码，当攻击 URL 为 <a href="http://xxx/?redirect_to=javascript:alert" target="_blank" rel="noopener">http://xxx/?redirect_to=javascript:alert</a>(‘XSS’)，服务端响应就成了：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"javascript:alert(<span class="symbol">&amp;#x27;</span>XSS<span class="symbol">&amp;#x27;</span>)"</span>&gt;</span>跳转...<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 根据项目情况进行过滤，禁止掉 "javascript:" 链接、非法 scheme 等</span></span><br><span class="line">allowSchemes = [<span class="string">"http"</span>, <span class="string">"https"</span>];</span><br><span class="line">valid = isValid(getParameter(<span class="string">"redirect_to"</span>), allowSchemes);</span><br><span class="line"><span class="keyword">if</span> (valid) &#123;</span><br><span class="line">  &lt;a href=<span class="string">"&lt;%= escapeHTML(getParameter("</span>redirect_to<span class="string">"))%&gt;"</span>&gt;</span><br><span class="line">    跳转...</span><br><span class="line">  &lt;<span class="regexp">/a&gt;</span></span><br><span class="line"><span class="regexp">&#125; else &#123;</span></span><br><span class="line"><span class="regexp">  &lt;a href="/</span><span class="number">404</span><span class="string">"&gt;</span></span><br><span class="line"><span class="string">    跳转...</span></span><br><span class="line"><span class="string">  &lt;/a&gt;</span></span><br><span class="line"><span class="string">&#125;</span></span><br></pre></td></tr></table></figure>
<p>根据上下文采用不同的转义规则<br>HTML 转义是非常复杂的，在不同的情况下要采用不同的转义规则。如果采用了错误的转义规则，很有可能会埋下 XSS 隐患。<br>应当尽量避免自己写转义库，而应当采用成熟的、业界通用的转义库。</p>
<p>漏洞总结<br>在 HTML 中内嵌的文本中，恶意内容以 script 标签形成注入。<br>在内联的 JavaScript 中，拼接的数据突破了原本的限制（字符串，变量，方法名等）。<br>在标签属性中，恶意内容包含引号，从而突破属性值的限制，注入其他属性或者标签。<br>在标签的 href、src 等属性中，包含 javascript: 等可执行代码。<br>在 onload、onerror、onclick 等事件中，注入不受控制代码。<br>在 style 属性和标签中，包含类似 background-image:url(“javascript:…”); 的代码（新版本浏览器已经可以防范）。<br>在 style 属性和标签中，包含类似 expression(…) 的 CSS 表达式代码（新版本浏览器已经可以防范）。<br>总之，如果开发者没有将用户输入的文本进行合适的过滤，就贸然插入到 HTML 中，这很容易造成注入漏洞。攻击者可以利用漏洞，构造出恶意的代码指令，进而利用恶意代码危害数据安全。</p>
<h4 id="React中对XSS如何进行XSS攻击和防范"><a href="#React中对XSS如何进行XSS攻击和防范" class="headerlink" title="React中对XSS如何进行XSS攻击和防范"></a>React中对XSS如何进行XSS攻击和防范</h4><p>prerender / SSR 的 hydrate 过程会生成 html ，需要小心测试其中是否有 XSS 漏洞。<br>dangerouslySetInnerHTML、onload=字符串、href=字符串 等，都有可能造成 XSS 漏洞。<br>所有的用户输入都需要经过HTML实体编码，这里React已经帮我们做了很多，它会在运行时动态创建DOM节点然后填入文本内容（你也可以强制设置HTML内容，不过这样比较危险）。<br>当你打算序列化某些状态并且传给客户端的时候，你同样需要进行HTML实体编码。<br>Yahoo的工程师已经提供了一个Serialize JavaScript模块帮我们轻松地进行JSON转码与过滤，我们可以直接使用npm install –save serialize-javascript导入该模块，然后使用serialize方法替代内置的JSON.stringify方法。</p>
<h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><p>常用排序算法快速排序、选择排序、堆排序。</p>
<h4 id="九宫格"><a href="#九宫格" class="headerlink" title="九宫格"></a>九宫格</h4><p>行坐标<code>colIndex</code>列坐标<code>rowIndex</code>和宫序号<code>boxIndex</code>宫内序号<code>cellIndex</code>的互相转换<br>宫坐标（Gx,Gy）。宫坐标的规律是，Gx是横坐标每3格＋1,Gy是纵坐标每3格＋1，所以要(col,row)转换成(Gx,Gy)就是把col和row分别/3取整，表示间隔了几次3格，得到的值就是（Gx,Gy）。((col/3),（row/3）)<br>宫序号boxIndex。我们把每个九宫格看成是一格，可以得出Gx每＋1就代表多1个九宫格，Gy每＋1就代表多3个九宫格。所以要计算宫序号，只要Gx＋Gy×3得到的值就是序号。(col/3)＋（row/3）×3<br>宫内格坐标。每3×3=9格是一个九宫格，图中总共有9个九宫格，然后每个九宫格都有自己的坐标从(0,0)-(2,2)。简单来说就是每隔3格，单元格的坐标就要重新计算。也就是说行列坐标对3求余表示当前的坐标遇3归0后剩下的值就是单元格的坐标。((colIndex%3),(rowIndex%3))<br>宫内序号cellIndex。每个九宫格都是一个独立的数组，要把九宫格里面的坐标转换成序号也是类似的。横坐标＋1表示单元格序号＋1，纵坐标+1表示单元格的序号+3。(colIndex%3)＋(rowIndex%3)×3</p>
<p>宫序号和宫内序号转换成行列坐标<br>因为Gx=col/3,Gy=row/3；所以col=Gx×3，row=Gy×3；(Gx×3,Gy×3)只是这个宫的左上角的坐标。根据宫内序号cellIndex可以得到cellIndex%3是宫内横坐标，cellIndex/3是宫内纵坐标。把宫内序号cellIndex代入可得((Gx×3＋cellIndex%3),(Gy×3＋cellIndex/3))。接下来根据宫序号boxIndex可以得到boxIndex%3是横坐标Gx，boxIndex/3是纵坐标Gy。最终用宫序号和宫内序号表示坐标。((boxIndex%3×3＋cellIndex%3),(boxIndex/3×3＋cellIndex/3))<br><img src="sudoku.png"></p>
<h4 id="Fisher-Yates-shuffle算法"><a href="#Fisher-Yates-shuffle算法" class="headerlink" title="Fisher-Yates shuffle算法"></a>Fisher-Yates shuffle算法</h4><p>该算法是用来打乱数组的顺序。<br>简单来说就是从左往右循环数组的每个项，每次把当前项和当前项之后的项（包括当前项）随机选择一个进行交换，但是如果随机到自己则不进行交换。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">shuffle(array)&#123;</span><br><span class="line">  <span class="comment">//最后一位只能选到自己，自己和自己不交换，所以最后一位就不考虑，所以把数组的长度减去1。</span></span><br><span class="line">  <span class="keyword">const</span> endIndex = array.length - <span class="number">1</span></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt;= endIndex; i++)&#123;</span><br><span class="line">      <span class="comment">//从当前位置之后（包括当前位置）随机取一个值进行交换。</span></span><br><span class="line">      <span class="keyword">const</span> j = i + <span class="built_in">Math</span>.floor(<span class="built_in">Math</span>.random() * (array.length - i));</span><br><span class="line">      <span class="comment">//es6解构赋值</span></span><br><span class="line">      [array[i], array[j]] = [array[j], array[i]]</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> array</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="shuffle.jpg"></p>
<h3 id="正则表达式"><a href="#正则表达式" class="headerlink" title="正则表达式"></a>正则表达式</h3><p>常用用法，exec，test，match。<br>test比较简单，返回表达式是否匹配上了字符串。匹配上了返回true，没匹配上返回false。<br>exec和match作用类似，不同的地方在于前者是字符串作为表达式的参数，后者是表达式作为字符串的参数。<br>还有就是正则表达式结合replace，可以使用子表达式来达到更灵活的替换规则。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> str = <span class="string">`console.log('123123')`</span></span><br><span class="line"><span class="keyword">let</span> reg = <span class="regexp">/(console.log\(')(\S+)('\))/</span></span><br><span class="line"><span class="keyword">let</span> execRes = reg.exec(str)</span><br><span class="line"><span class="built_in">console</span>.log(execRes)</span><br><span class="line"><span class="keyword">let</span> testRes = reg.test(str)</span><br><span class="line"><span class="built_in">console</span>.log(testRes)</span><br><span class="line"><span class="keyword">let</span> matchRes = str.match(reg)</span><br><span class="line"><span class="built_in">console</span>.log(matchRes)</span><br><span class="line"><span class="built_in">console</span>.log(str)</span><br><span class="line">str = str.replace(<span class="regexp">/(console.log\(')(.*)('\))/g</span>, <span class="string">`$1当前版本<span class="subst">$&#123;<span class="keyword">new</span> <span class="built_in">Date</span>().toLocaleString()&#125;</span>$3`</span> )</span><br><span class="line"><span class="built_in">console</span>.log(str)</span><br></pre></td></tr></table></figure>
<h2 id="前沿技术"><a href="#前沿技术" class="headerlink" title="前沿技术"></a>前沿技术</h2><h3 id="http2"><a href="#http2" class="headerlink" title="http2"></a>http2</h3><p>演示地址<a href="https://http2.akamai.com/demo" target="_blank" rel="noopener">https://http2.akamai.com/demo</a></p>
<h3 id="pwa"><a href="#pwa" class="headerlink" title="pwa"></a>pwa</h3><h3 id="webpack多个入口，单页面应用与多个入口页面"><a href="#webpack多个入口，单页面应用与多个入口页面" class="headerlink" title="webpack多个入口，单页面应用与多个入口页面"></a>webpack多个入口，单页面应用与多个入口页面</h3><h3 id="微前端乾坤"><a href="#微前端乾坤" class="headerlink" title="微前端乾坤"></a>微前端乾坤</h3><h3 id="module-bundle-chunk"><a href="#module-bundle-chunk" class="headerlink" title="module bundle chunk"></a>module bundle chunk</h3>
      
    </div>

    

    
    
    

    

    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/blog/tags/前端基础/" rel="tag"># 前端基础</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/blog/2017/11/01/blog/programming-and-algorithms/programming-and-algorithms/" rel="next" title="JavaScript程序和算法">
                <i class="fa fa-chevron-left"></i> JavaScript程序和算法
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/blog/2017/11/03/blog/web-front-end-performance/web-front-end-performance/" rel="prev" title="前端性能优化">
                前端性能优化 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>


  </div>


          </div>
          

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">对美好事物的向往，心中要充满强烈的愿望！</p>
              <p class="site-description motion-element" itemprop="description">沉淀下来的知识，才是真正的财富！</p>
          </div>

          
            <nav class="site-state motion-element">
              
                <div class="site-state-item site-state-posts">
                
                  <a href="/blog/archives/">
                
                    <span class="site-state-item-count">19</span>
                    <span class="site-state-item-name">日志</span>
                  </a>
                </div>
              

              
                
                
                <div class="site-state-item site-state-categories">
                  <a href="/blog/categories/index.html">
                    
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                    <span class="site-state-item-count">22</span>
                    <span class="site-state-item-name">分类</span>
                  </a>
                </div>
              

              
                
                
                <div class="site-state-item site-state-tags">
                  <a href="/blog/tags/index.html">
                    
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                      
                    
                    <span class="site-state-item-count">19</span>
                    <span class="site-state-item-name">标签</span>
                  </a>
                </div>
              
            </nav>
          

          

          

          
          

          
          

          
            
          
          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#JS基础"><span class="nav-number">1.</span> <span class="nav-text">JS基础</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#原型和原型链"><span class="nav-number">1.1.</span> <span class="nav-text">原型和原型链</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#基本理解"><span class="nav-number">1.1.1.</span> <span class="nav-text">基本理解</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#实际应用"><span class="nav-number">1.1.2.</span> <span class="nav-text">实际应用</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#创建对象"><span class="nav-number">1.1.2.1.</span> <span class="nav-text">创建对象</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#判断类型"><span class="nav-number">1.1.2.2.</span> <span class="nav-text">判断类型</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#继承重写"><span class="nav-number">1.1.2.3.</span> <span class="nav-text">继承重写</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#作用域及闭包"><span class="nav-number">1.2.</span> <span class="nav-text">作用域及闭包</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#作用域"><span class="nav-number">1.2.1.</span> <span class="nav-text">作用域</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#闭包官方定义"><span class="nav-number">1.2.2.</span> <span class="nav-text">闭包官方定义</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#我对闭包的理解"><span class="nav-number">1.2.3.</span> <span class="nav-text">我对闭包的理解</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#为什么要用"><span class="nav-number">1.2.4.</span> <span class="nav-text">为什么要用</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#如果不想过多的使用闭包可以考虑使用let"><span class="nav-number">1.2.5.</span> <span class="nav-text">如果不想过多的使用闭包可以考虑使用let</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#异步和单线程"><span class="nav-number">1.3.</span> <span class="nav-text">异步和单线程</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#基本理解-1"><span class="nav-number">1.3.1.</span> <span class="nav-text">基本理解</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#前置知识"><span class="nav-number">1.3.1.1.</span> <span class="nav-text">前置知识</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#任务队列"><span class="nav-number">1.3.1.2.</span> <span class="nav-text">任务队列</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#执行过程"><span class="nav-number">1.3.1.3.</span> <span class="nav-text">执行过程</span></a></li></ol></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#HTML-CSS"><span class="nav-number">2.</span> <span class="nav-text">HTML/CSS</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#盒模型"><span class="nav-number">2.1.</span> <span class="nav-text">盒模型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#布局方式"><span class="nav-number">2.2.</span> <span class="nav-text">布局方式</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#float"><span class="nav-number">2.2.1.</span> <span class="nav-text">float</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#absolute"><span class="nav-number">2.2.2.</span> <span class="nav-text">absolute</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#flex"><span class="nav-number">2.2.3.</span> <span class="nav-text">flex</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#table"><span class="nav-number">2.2.4.</span> <span class="nav-text">table</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#grid"><span class="nav-number">2.2.5.</span> <span class="nav-text">grid</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#渲染机制"><span class="nav-number">2.3.</span> <span class="nav-text">渲染机制</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#加载过程"><span class="nav-number">2.3.1.</span> <span class="nav-text">加载过程</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#渲染过程"><span class="nav-number">2.3.2.</span> <span class="nav-text">渲染过程</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#综合知识"><span class="nav-number">3.</span> <span class="nav-text">综合知识</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#this"><span class="nav-number">3.1.</span> <span class="nav-text">this</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#基本理解-2"><span class="nav-number">3.1.1.</span> <span class="nav-text">基本理解</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#this-bind-call-apply"><span class="nav-number">3.1.2.</span> <span class="nav-text">this,bind,call,apply</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Ajax"><span class="nav-number">3.2.</span> <span class="nav-text">Ajax</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#ES6"><span class="nav-number">3.3.</span> <span class="nav-text">ES6</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#基本介绍"><span class="nav-number">3.3.1.</span> <span class="nav-text">基本介绍</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#箭头函数"><span class="nav-number">3.3.2.</span> <span class="nav-text">箭头函数</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Promise"><span class="nav-number">3.3.3.</span> <span class="nav-text">Promise</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#基本介绍-1"><span class="nav-number">3.3.3.1.</span> <span class="nav-text">基本介绍</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#手写Promise"><span class="nav-number">3.3.3.2.</span> <span class="nav-text">手写Promise</span></a></li></ol></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Generator"><span class="nav-number">3.3.4.</span> <span class="nav-text">Generator</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#async-await"><span class="nav-number">3.3.5.</span> <span class="nav-text">async/await</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#数组"><span class="nav-number">3.4.</span> <span class="nav-text">数组</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#常用方法"><span class="nav-number">3.4.1.</span> <span class="nav-text">常用方法</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#数组去重"><span class="nav-number">3.4.2.</span> <span class="nav-text">数组去重</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#循环方法的区别"><span class="nav-number">3.4.3.</span> <span class="nav-text">循环方法的区别</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#事件代理"><span class="nav-number">3.5.</span> <span class="nav-text">事件代理</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#DOM0-事件"><span class="nav-number">3.5.1.</span> <span class="nav-text">DOM0 事件</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#DOM2-事件"><span class="nav-number">3.5.2.</span> <span class="nav-text">DOM2 事件</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#DOM3事件"><span class="nav-number">3.5.3.</span> <span class="nav-text">DOM3事件</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#拷贝"><span class="nav-number">3.6.</span> <span class="nav-text">拷贝</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#乞丐版"><span class="nav-number">3.6.1.</span> <span class="nav-text">乞丐版</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#基础版本"><span class="nav-number">3.6.2.</span> <span class="nav-text">基础版本</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#考虑数组"><span class="nav-number">3.6.3.</span> <span class="nav-text">考虑数组</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#循环引用"><span class="nav-number">3.6.4.</span> <span class="nav-text">循环引用</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#性能优化"><span class="nav-number">3.6.5.</span> <span class="nav-text">性能优化</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#数据类型"><span class="nav-number">3.7.</span> <span class="nav-text">数据类型</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#基本介绍-2"><span class="nav-number">3.7.1.</span> <span class="nav-text">基本介绍</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#赋值"><span class="nav-number">3.7.2.</span> <span class="nav-text">赋值</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#栈和堆"><span class="nav-number">3.7.3.</span> <span class="nav-text">栈和堆</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#比较"><span class="nav-number">3.7.4.</span> <span class="nav-text">比较</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Symbol"><span class="nav-number">3.7.5.</span> <span class="nav-text">Symbol</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#NaN"><span class="nav-number">3.7.6.</span> <span class="nav-text">NaN</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#undefined-和-null"><span class="nav-number">3.7.7.</span> <span class="nav-text">undefined 和 null</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#和"><span class="nav-number">3.7.8.</span> <span class="nav-text">== 和 ===</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#判断类型-1"><span class="nav-number">3.7.9.</span> <span class="nav-text">判断类型</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#defineProperty"><span class="nav-number">3.8.</span> <span class="nav-text">defineProperty</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#数据描述符和存取描述符共有的配置"><span class="nav-number">3.8.1.</span> <span class="nav-text">数据描述符和存取描述符共有的配置</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#数据描述符特有的配置"><span class="nav-number">3.8.2.</span> <span class="nav-text">数据描述符特有的配置</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#存取描述符特有的配置"><span class="nav-number">3.8.3.</span> <span class="nav-text">存取描述符特有的配置</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#实际应用-1"><span class="nav-number">3.8.4.</span> <span class="nav-text">实际应用</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#resuestAnimationFrame"><span class="nav-number">3.9.</span> <span class="nav-text">resuestAnimationFrame</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#setTimeout和setInterval"><span class="nav-number">3.10.</span> <span class="nav-text">setTimeout和setInterval</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#setTimeout"><span class="nav-number">3.10.1.</span> <span class="nav-text">setTimeout</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#setInterval"><span class="nav-number">3.10.2.</span> <span class="nav-text">setInterval</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#代码"><span class="nav-number">3.11.</span> <span class="nav-text">代码</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#原型和原型链-1"><span class="nav-number">3.11.1.</span> <span class="nav-text">原型和原型链</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#箭头函数this指向"><span class="nav-number">3.11.2.</span> <span class="nav-text">箭头函数this指向</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#EventLoop"><span class="nav-number">3.11.3.</span> <span class="nav-text">EventLoop</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#下划线命名到驼峰命名"><span class="nav-number">3.11.4.</span> <span class="nav-text">下划线命名到驼峰命名</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#防抖和节流"><span class="nav-number">3.11.5.</span> <span class="nav-text">防抖和节流</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#将原生ajax封装到Promise"><span class="nav-number">3.11.6.</span> <span class="nav-text">将原生ajax封装到Promise</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#实现sleep"><span class="nav-number">3.11.7.</span> <span class="nav-text">实现sleep</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#实现bind"><span class="nav-number">3.11.8.</span> <span class="nav-text">实现bind</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#场景"><span class="nav-number">3.12.</span> <span class="nav-text">场景</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#计算一年多少周"><span class="nav-number">3.12.1.</span> <span class="nav-text">计算一年多少周</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#轮播图实现原理"><span class="nav-number">3.12.2.</span> <span class="nav-text">轮播图实现原理</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Java和JavaScript的区别"><span class="nav-number">3.12.3.</span> <span class="nav-text">Java和JavaScript的区别</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#通用性能优化"><span class="nav-number">3.12.4.</span> <span class="nav-text">通用性能优化</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#实现拖拽"><span class="nav-number">3.12.5.</span> <span class="nav-text">实现拖拽</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#前端模块化"><span class="nav-number">3.12.6.</span> <span class="nav-text">前端模块化</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#一次加载一张图片，加载完后再加载下一张"><span class="nav-number">3.12.7.</span> <span class="nav-text">一次加载一张图片，加载完后再加载下一张</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#其他"><span class="nav-number">3.13.</span> <span class="nav-text">其他</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#js字符串转数字的方法"><span class="nav-number">3.13.1.</span> <span class="nav-text">js字符串转数字的方法</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#eval"><span class="nav-number">3.13.2.</span> <span class="nav-text">eval</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#with"><span class="nav-number">3.13.3.</span> <span class="nav-text">with</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#setTimeout-fn-100"><span class="nav-number">3.13.4.</span> <span class="nav-text">setTimeout(fn,100)</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#去除字符串首尾空格"><span class="nav-number">3.13.5.</span> <span class="nav-text">去除字符串首尾空格</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#indexOf和startWith的区别"><span class="nav-number">3.13.6.</span> <span class="nav-text">indexOf和startWith的区别</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#图片的懒加载和预加载"><span class="nav-number">3.13.7.</span> <span class="nav-text">图片的懒加载和预加载</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#参数获取"><span class="nav-number">3.13.8.</span> <span class="nav-text">参数获取</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#暂停死区"><span class="nav-number">3.13.9.</span> <span class="nav-text">暂停死区</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#js垃圾回收机制"><span class="nav-number">3.13.10.</span> <span class="nav-text">js垃圾回收机制</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#var-let-const的区别"><span class="nav-number">3.13.11.</span> <span class="nav-text">var let const的区别</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#获得对象上的属性"><span class="nav-number">3.13.12.</span> <span class="nav-text">获得对象上的属性</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#利用js保留关键字arguments获取函数参数"><span class="nav-number">3.13.13.</span> <span class="nav-text">利用js保留关键字arguments获取函数参数</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#js中的各种位置"><span class="nav-number">3.13.14.</span> <span class="nav-text">js中的各种位置</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#变量提升"><span class="nav-number">3.13.15.</span> <span class="nav-text">变量提升</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#计算机网络"><span class="nav-number">4.</span> <span class="nav-text">计算机网络</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#CDN原理"><span class="nav-number">4.1.</span> <span class="nav-text">CDN原理</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#输入url"><span class="nav-number">4.2.</span> <span class="nav-text">输入url</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#head请求option"><span class="nav-number">4.3.</span> <span class="nav-text">head请求option</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#OSI七层模型"><span class="nav-number">4.4.</span> <span class="nav-text">OSI七层模型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#TCP-IP的网络模型"><span class="nav-number">4.5.</span> <span class="nav-text">TCP/IP的网络模型</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#HTTP状态码"><span class="nav-number">4.6.</span> <span class="nav-text">HTTP状态码</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#跨域"><span class="nav-number">4.7.</span> <span class="nav-text">跨域</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#JSONP"><span class="nav-number">4.7.1.</span> <span class="nav-text">JSONP</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#cors"><span class="nav-number">4.7.2.</span> <span class="nav-text">cors</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#服务器代理"><span class="nav-number">4.7.3.</span> <span class="nav-text">服务器代理</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#location-hash-iframe跨域"><span class="nav-number">4.7.4.</span> <span class="nav-text">location.hash + iframe跨域</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#window-name-iframe跨域"><span class="nav-number">4.7.5.</span> <span class="nav-text">window.name + iframe跨域</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#postMessage跨域"><span class="nav-number">4.7.6.</span> <span class="nav-text">postMessage跨域</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#token"><span class="nav-number">4.7.7.</span> <span class="nav-text">token</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#HTTP缓存机制"><span class="nav-number">4.8.</span> <span class="nav-text">HTTP缓存机制</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#强缓存和协商缓存"><span class="nav-number">4.8.1.</span> <span class="nav-text">强缓存和协商缓存</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#强缓存"><span class="nav-number">4.8.2.</span> <span class="nav-text">强缓存</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#协商缓存"><span class="nav-number">4.8.3.</span> <span class="nav-text">协商缓存</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#TCP三次握手"><span class="nav-number">4.9.</span> <span class="nav-text">TCP三次握手</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#报文内容介绍"><span class="nav-number">4.9.1.</span> <span class="nav-text">报文内容介绍</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#序列号和确认号"><span class="nav-number">4.9.2.</span> <span class="nav-text">序列号和确认号</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#SYN和ACK标志位"><span class="nav-number">4.9.3.</span> <span class="nav-text">SYN和ACK标志位</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#状态"><span class="nav-number">4.9.4.</span> <span class="nav-text">状态</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#常见问题"><span class="nav-number">4.9.5.</span> <span class="nav-text">常见问题</span></a><ol class="nav-child"><li class="nav-item nav-level-5"><a class="nav-link" href="#TCP和UDP的区别"><span class="nav-number">4.9.5.1.</span> <span class="nav-text">TCP和UDP的区别</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#TCP为什么是三次而不是两次、四次"><span class="nav-number">4.9.5.2.</span> <span class="nav-text">TCP为什么是三次而不是两次、四次?</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#TCP如何保证可靠性"><span class="nav-number">4.9.5.3.</span> <span class="nav-text">TCP如何保证可靠性</span></a></li><li class="nav-item nav-level-5"><a class="nav-link" href="#POST和GET的区别"><span class="nav-number">4.9.5.4.</span> <span class="nav-text">POST和GET的区别</span></a></li></ol></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#HTTP协议"><span class="nav-number">4.10.</span> <span class="nav-text">HTTP协议</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#HTTPS"><span class="nav-number">4.10.1.</span> <span class="nav-text">HTTPS</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#HTTP2-0"><span class="nav-number">4.10.2.</span> <span class="nav-text">HTTP2.0</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#安全"><span class="nav-number">4.11.</span> <span class="nav-text">安全</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#XSS和CSRF"><span class="nav-number">4.11.1.</span> <span class="nav-text">XSS和CSRF</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#理解CSRF，记住几句话"><span class="nav-number">4.11.2.</span> <span class="nav-text">理解CSRF，记住几句话</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#XSS-漏洞的发生和修复"><span class="nav-number">4.11.3.</span> <span class="nav-text">XSS 漏洞的发生和修复</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#React中对XSS如何进行XSS攻击和防范"><span class="nav-number">4.11.4.</span> <span class="nav-text">React中对XSS如何进行XSS攻击和防范</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#算法"><span class="nav-number">4.12.</span> <span class="nav-text">算法</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#九宫格"><span class="nav-number">4.12.1.</span> <span class="nav-text">九宫格</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Fisher-Yates-shuffle算法"><span class="nav-number">4.12.2.</span> <span class="nav-text">Fisher-Yates shuffle算法</span></a></li></ol></li><li class="nav-item nav-level-3"><a class="nav-link" href="#正则表达式"><span class="nav-number">4.13.</span> <span class="nav-text">正则表达式</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#前沿技术"><span class="nav-number">5.</span> <span class="nav-text">前沿技术</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#http2"><span class="nav-number">5.1.</span> <span class="nav-text">http2</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#pwa"><span class="nav-number">5.2.</span> <span class="nav-text">pwa</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#webpack多个入口，单页面应用与多个入口页面"><span class="nav-number">5.3.</span> <span class="nav-text">webpack多个入口，单页面应用与多个入口页面</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#微前端乾坤"><span class="nav-number">5.4.</span> <span class="nav-text">微前端乾坤</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#module-bundle-chunk"><span class="nav-number">5.5.</span> <span class="nav-text">module bundle chunk</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright"> &copy; <span itemprop="copyrightYear">2024</span>
  <span class="with-love" id="animate">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">对美好事物的向往，心中要充满强烈的愿望！</span>

  

  
</div>




  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动 v3.9.0</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 – <a class="theme-link" target="_blank" href="https://theme-next.org">NexT.Gemini</a> v6.4.2</div>




        








        
        <div>
          <a href="https://beian.miit.gov.cn/" target="_blank">闽ICP备15015722号-2</a>
        </div>
      </div>
     
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    
	
    

    
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>


























  
  
    <script type="text/javascript" src="/blog/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/blog/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  


  


  <script type="text/javascript" src="/blog/js/src/utils.js?v=6.4.2"></script>

  <script type="text/javascript" src="/blog/js/src/motion.js?v=6.4.2"></script>



  
  


  <script type="text/javascript" src="/blog/js/src/affix.js?v=6.4.2"></script>

  <script type="text/javascript" src="/blog/js/src/schemes/pisces.js?v=6.4.2"></script>



  
  <script type="text/javascript" src="/blog/js/src/scrollspy.js?v=6.4.2"></script>
<script type="text/javascript" src="/blog/js/src/post-details.js?v=6.4.2"></script>



  


  <script type="text/javascript" src="/blog/js/src/bootstrap.js?v=6.4.2"></script>



  



  










  





  

  

  

  

  

  
  

  

  

  

  

  

</body>
</html>
